الفرق بين المراجعتين لصفحة: «ReactNative/gesture responder system»

من موسوعة حسوب
ط مراجعة
سطر 1: سطر 1:
<noinclude>{{DISPLAYTITLE: نظام مستجيب الإيماءات في React Native}}</noinclude>
<noinclude>{{DISPLAYTITLE: نظام مستجيب الإيماءات في React Native}}</noinclude>يدير نظام مستجيب الإيماءات (Gesture Responder System) دورة حياة الإيماءات في تطبيقك. يمكن لِلَمسةٍ أن تمرّ عبر عدة مراحل بينما يحدّد التطبيق نيّةَ المستخدم. على سبيل المثال، يحتاج التطبيق إلى تحديد ما إذا كانت اللمسة تمرِّرُ (scrolling) أو تنزلق (sliding) على أداةٍ (widget) أو أن اللمسَة أرِيد منها الضغطُ على زر معيّن. يمكن لهذا أن يتغير حتى أثناء اللمس. ويمكن أن يكون هناك أيضًا العديد من اللمسات المتزامنة.


== نظام مستجيب الإيماءات (Gesture Responder System) ==
نحتاج إلى نظام مستجيب الإيماءات للسماح للمكونات بالتعامل مع هذه اللمسات التفاعليّة دون أي معرفة إضافية عن المكون الأب أو الأبناء.
يدير نظام مستجيب الإيماءات دورة حياة (lifecycle) الإيماءات في تطبيقك. يمكن لِلَمسةٍ أن تمرّ عبر عدة مراحل بينما يحدّد التطبيق نيّةَ المستخدم. على سبيل المثال، يحتاج التطبيق إلى تحديد ما إذا كانت اللمسة تمرِّرُ (scrolling) أو تنزلق (sliding) على أداةٍ (widget) أو أن اللمسَة أرِيد منها الضغطُ على زر معيّن. يمكن لهذا أن يتغير حتى أثناء اللمس. ويمكن أن يكون هناك أيضًا العديد من اللمسات المتزامنة.
 
نحتاج إلى نظام مستجيب الإيماءات للسماح للمكونات بالتعامل مع هذه اللمسات التفاعليّة دون أي معرفة إضافية عن المكون الأب أو الأطفال.


==أفضل الممارسات==
==أفضل الممارسات==
سطر 18: سطر 15:


==دورة حياة المستجيب (Responder Lifecycle)==
==دورة حياة المستجيب (Responder Lifecycle)==
يمكن لِعرضٍ (view) أن يُصبِح مستجيبًا للّمس عبر استخدام التوابع المناسبة. هناك تابعان يُمكن بهما تحويل العرض إلى مستجيب:
يمكن لواجهة (view) أن تستجيب للّمس عبر استخدام التوابع المناسبة. هناك تابعان يُمكن بهما تحويل الواجهة إلى مستجيبة يعتمد استعمال أحدهما على الإجابة على أحد السؤالين:
 
* ‎‎<code>View.props.onStartShouldSetResponder: (evt) => true,</code>‎‎:هل تُريد تحويل هذا العرض إلى مستجيبٍ عند بدء اللمس؟
 
* ‎‎<code>View.props.onMoveShouldSetResponder: (evt) => true,</code>‎‎:يُستدعى لكل حركة لمسٍ في العرض عندما لا يكونُ مستجيبًا: هل يريد هذا العرض "المطالبة (claim)" بالاستجابة للمس؟


إذا أعاد العرض القيمة ‎‎<code>true</code>‎‎ وحاول أن يُصبِح المستجيبَ للإيماءة، فسيحدث أحد الأمور التالية:
* هل تُريد تحويل هذه الواجهة إلى مستجيبٍ عند بدء لمسها؟
<syntaxhighlight lang="js">
View.props.onStartShouldSetResponder: (evt) => true
</syntaxhighlight>
* يُستدعى لكل حركة لمسٍ في الواجهة <code>View</code> عندما لا تكونُ المستجيبة: هل يريد هذه الواجهة "المطالبة (claim)" بالاستجابة للمس؟
<syntaxhighlight lang="js">
‎‎View.props.onMoveShouldSetResponder: (evt) => true
</syntaxhighlight>إذا أعادت الواجهة القيمة ‎‎<code>true</code>‎‎ وحاولت أن تصبِح المستجيبَ للإيماءة، فسيحدث أحد الأمور التالية:


*‎‎<code>View.props.onResponderGrant: (evt) => {}</code>‎‎: يستجيب العرضُ الآن لأحداث اللمس. هذا هو الوقت المناسب لإبراز وإظهار ما يحدث للمستخدم.
*‎‎<code>View.props.onResponderGrant: (evt) => {}</code>‎‎: تستجيب الواجهة الآن لأحداث اللمس. هذا هو الوقت المناسب لإبراز وإظهار ما يحدث للمستخدم.
*‎‎<code>View.props.onResponderReject: (evt) => {}</code>‎‎: يعمل عرضٌ آخرٌ بصفة المستجيب الآنَ ولن يُحرِّر (release) الإيماءة.
*‎‎<code>View.props.onResponderReject: (evt) => {}</code>‎‎: واجهة أخرى هي المستجيبة الآنَ ولن تُحرِّر (release) الإيماءة.


إذا كان العرض يستجيب، فيمكن استدعاء معالجات الأحداث التالية:
إذا كانت الواجهة تستجيب، فيمكن استدعاء معالجات الأحداث التالية:
*‎‎<code>View.props.onResponderMove: (evt) => {}</code>‎‎: يُحرِّك المستخدم إصبعه.
*‎‎<code>View.props.onResponderMove: (evt) => {}</code>‎‎: يُحرِّك المستخدم إصبعه.
*‎‎<code>View.props.onResponderRelease: (evt) => {}</code>‎‎: يُطلَق في نهاية اللمسة، أي الحدث "touchUp".
*‎‎<code>View.props.onResponderRelease: (evt) => {}</code>‎‎: يُطلَق في نهاية اللمسة، أي الحدث "touchUp".
*‎‎<code>View.props.onResponderTerminationRequest: (evt) => true</code>‎‎: هناك عرضٌ آخر يريد أن يصبح مجيبًا. هل يُحرِّر (release) هذا العرض المُستجيب؟ إعادة القيمة ‎‎<code>true</code>‎‎ يسمح بتحرير المستجيب.
*‎‎<code>View.props.onResponderTerminationRequest: (evt) => true</code>‎‎: هناك واجهة أخرى تريد أن تصبح مستجيبة. هل تحرِّر (release) هذه الواجهة المُستجيب؟ إعادة القيمة ‎‎<code>true</code>‎‎ يسمح بتحرير المستجيب.
*‎‎<code>View.props.onResponderTerminate: (evt) => {}</code>‎‎: أُخِذَ المستجيب من العرض. قد يُؤخَذ من طرف عروضٍ أخرى بعد استدعاء ‎‎<code>onResponderTerminationRequest</code>‎‎، أو قد يُؤخَذ من طرف نظام التشغيل دون أي طلبٍ مُسبَق (يحدث هذا عبر مركز التحكم أو مركز الإشعارات على iOS).
*‎‎<code>View.props.onResponderTerminate: (evt) => {}</code>‎‎: أُخِذَ المستجيب من الواجهة. قد يُؤخَذ من طرف واجهات أخرى بعد استدعاء ‎‎<code>onResponderTerminationRequest</code>‎‎، أو قد يُؤخَذ من طرف نظام التشغيل دون أي طلبٍ مُسبَق (يحدث هذا عبر مركز التحكم أو مركز الإشعارات على iOS).


<code>evt</code> حدثُ لمسةٍ اصطناعيّ (synthetic touch event) ذو الشكل التالي:
<code>evt</code> حدثُ لمسةٍ اصطناعيّ (synthetic touch event) ذو الشكل التالي:
سطر 48: سطر 48:
** ‎‎<code>touches</code>‎‎: مصفوفة جميع اللمسات الحالية على الشاشة.
** ‎‎<code>touches</code>‎‎: مصفوفة جميع اللمسات الحالية على الشاشة.


===التقاط مُعالجات ShouldSet===
===التقاط معالجات ShouldSet===
يُستدعَى ‎‎<code>onStartShouldSetResponder</code>‎‎ و‎‎<code>onMoveShouldSetResponder</code>‎‎ بنمط فقاعي (bubbling pattern)، حيث تُستدعَى العقدة الأعمق أولاً. هذا يعني أن العنصر الأعمق سوف يصبح المُستجيب عندما تُعيد عروضٌ متعددة القيمةَ ‎‎true‎‎ لمعالجات ‎‎<code>*ShouldSetResponder</code>‎‎. هذا أمر مرغوب فيه في معظم الحالات، لأنه يتأكد من أن جميع عناصر التحكم والأزرار قابلة للاستخدام.
يُستدعَى الحدث ‎‎<code>onStartShouldSetResponder</code>‎‎ والحدث ‎‎<code>onMoveShouldSetResponder</code>‎‎ بنمط فقاعي (bubbling pattern)، حيث تُستدعَى العقدة الأعمق أولاً. هذا يعني أن العنصر الأعمق سوف يصبح المُستجيب عندما تُعيد واجهات متعددة القيمةَ ‎‎<code>true‎‎</code> لمعالجات ‎‎<code>*ShouldSetResponder</code>‎‎. هذا أمر مرغوب فيه في معظم الحالات، لأنه يتأكد من أن جميع عناصر التحكم والأزرار قابلة للاستخدام.
 
ومع ذلك، أحيانًا قد يرغب مُكوِّنٌ أبٌ في التّأكد من أنه سيصبح المستجيب. يمكن التعامل مع هذه الحالة عن طريق استخدام مرحلة الالتقاط (capture phase). قبل أن يصعد نظام المستجيب من المكوّن الأعمق إلى أعلى، سيمرّ بمرحلة التقاط، مُطلِقًا ‎‎<code>on*ShouldSetResponderCapture</code>‎‎. لذا، إذا أراد مكونٌ أبٌ منع الطفل من أن يصبح مستجيبًا عند بدء اللمس، فيجب أن يحتوي على معالج ‎‎<code>onStartShouldSetResponderCapture</code>‎‎ يقوم بإرجاع القيمة true.


* ‎‎<code>View.props.onStartShouldSetResponderCapture: (evt) => true,</code>‎‎
ومع ذلك، أحيانًا قد يرغب مُكوِّنٌ أبٌ في التّأكد من أنه سيصبح المستجيب. يمكن التعامل مع هذه الحالة عن طريق استخدام مرحلة الالتقاط (capture phase). قبل أن يصعد نظام المستجيب من المكوّن الأعمق إلى أعلى، سيمرّ بمرحلة التقاط، مُطلِقًا ‎‎<code>on*ShouldSetResponderCapture</code>‎‎. لذا، إذا أراد مكونٌ أبٌ منع الطفل من أن يصبح مستجيبًا عند بدء اللمس، فيجب أن يحتوي على معالج ‎‎<code>onStartShouldSetResponderCapture</code>‎‎ يقوم بإرجاع القيمة <code>true</code>.<syntaxhighlight lang="js">
* ‎‎<code>View.props.onMoveShouldSetResponderCapture: (evt) => true,</code>‎‎
‎‎View.props.onStartShouldSetResponderCapture: (evt) => true,‎‎
‎‎View.props.onMoveShouldSetResponderCapture: (evt) => true,‎‎
</syntaxhighlight>


=== PanResponder ===
=== المستجيب PanResponder ===
لتفسير الإيماءات على مستوًى أعلى (higher-level)، انظر [[ReactNative/panresponder|PanResponder]].
لتفسير الإيماءات على مستوًى أعلى (higher-level)، انظر [[ReactNative/panresponder|<code>PanResponder</code>]].


== مصادر ==
== مصادر ==
* [https://facebook.github.io/react-native/docs/gesture-responder-system صفحة Gesture Responder System في توثيق React Native الرسمي.]
* [https://facebook.github.io/react-native/docs/gesture-responder-system صفحة Gesture Responder System في توثيق React Native الرسمي.]
[[تصنيف:ReactNative]]
[[تصنيف:ReactNative]]

مراجعة 08:41، 2 سبتمبر 2021

يدير نظام مستجيب الإيماءات (Gesture Responder System) دورة حياة الإيماءات في تطبيقك. يمكن لِلَمسةٍ أن تمرّ عبر عدة مراحل بينما يحدّد التطبيق نيّةَ المستخدم. على سبيل المثال، يحتاج التطبيق إلى تحديد ما إذا كانت اللمسة تمرِّرُ (scrolling) أو تنزلق (sliding) على أداةٍ (widget) أو أن اللمسَة أرِيد منها الضغطُ على زر معيّن. يمكن لهذا أن يتغير حتى أثناء اللمس. ويمكن أن يكون هناك أيضًا العديد من اللمسات المتزامنة.

نحتاج إلى نظام مستجيب الإيماءات للسماح للمكونات بالتعامل مع هذه اللمسات التفاعليّة دون أي معرفة إضافية عن المكون الأب أو الأبناء.

أفضل الممارسات

لتحسين التعامل مع تطبيقك، يجب أن يحتوي كل إجراءٍ على السمات التالية:

  • ردة فعل (Feedback) أو إبراز (highlighting): أظهر للمستخدم الجزء الذي يتعامل مع إيماءة اللمس، وما سيحدث عند إطلاق هذه الإيماءة.
  • القدرة على الإلغاء: عند القيام بإجراء ما، يجب أن يكون المستخدم قادرًا على إلغائه في منتصف حركة اللمس عن طريق سحب إصبعه بعيدًا.

تُضيف هذه الميزاتُ أريحيّةً أكثر لمستخدمي التطبيق، لأنها تسمح للأشخاص بتجربة الميّزات والتفاعل دون الخوف من ارتكاب الأخطاء.

مكون ‎‎TouchableHighlight‎‎ ومكونات ‎‎Touchable*‎‎ القابلة للمس

يمكن أن يكون استخدام نظام المستجيب (responder system) معقدًا. لذا يحتوي إطار العمل على ميّزة ‎‎Touchable‎‎ تجريديّة (abstract) لما يُمكن لمسُه (tappable). يستخدم هذا نظامَ المستجيب ويسمح لك بإعداد تفاعلات اللمس تصريحيًّا (declaratively) بسهولة. استخدم TouchableHighlight في أي مكان قد تستخدم فيه زرًّا أو رابطًا على الويب.

دورة حياة المستجيب (Responder Lifecycle)

يمكن لواجهة (view) أن تستجيب للّمس عبر استخدام التوابع المناسبة. هناك تابعان يُمكن بهما تحويل الواجهة إلى مستجيبة يعتمد استعمال أحدهما على الإجابة على أحد السؤالين:

  • هل تُريد تحويل هذه الواجهة إلى مستجيبٍ عند بدء لمسها؟
View.props.onStartShouldSetResponder: (evt) => true
  • يُستدعى لكل حركة لمسٍ في الواجهة View عندما لا تكونُ المستجيبة: هل يريد هذه الواجهة "المطالبة (claim)" بالاستجابة للمس؟
‎‎View.props.onMoveShouldSetResponder: (evt) => true

إذا أعادت الواجهة القيمة ‎‎true‎‎ وحاولت أن تصبِح المستجيبَ للإيماءة، فسيحدث أحد الأمور التالية:

  • ‎‎View.props.onResponderGrant: (evt) => {}‎‎: تستجيب الواجهة الآن لأحداث اللمس. هذا هو الوقت المناسب لإبراز وإظهار ما يحدث للمستخدم.
  • ‎‎View.props.onResponderReject: (evt) => {}‎‎: واجهة أخرى هي المستجيبة الآنَ ولن تُحرِّر (release) الإيماءة.

إذا كانت الواجهة تستجيب، فيمكن استدعاء معالجات الأحداث التالية:

  • ‎‎View.props.onResponderMove: (evt) => {}‎‎: يُحرِّك المستخدم إصبعه.
  • ‎‎View.props.onResponderRelease: (evt) => {}‎‎: يُطلَق في نهاية اللمسة، أي الحدث "touchUp".
  • ‎‎View.props.onResponderTerminationRequest: (evt) => true‎‎: هناك واجهة أخرى تريد أن تصبح مستجيبة. هل تحرِّر (release) هذه الواجهة المُستجيب؟ إعادة القيمة ‎‎true‎‎ يسمح بتحرير المستجيب.
  • ‎‎View.props.onResponderTerminate: (evt) => {}‎‎: أُخِذَ المستجيب من الواجهة. قد يُؤخَذ من طرف واجهات أخرى بعد استدعاء ‎‎onResponderTerminationRequest‎‎، أو قد يُؤخَذ من طرف نظام التشغيل دون أي طلبٍ مُسبَق (يحدث هذا عبر مركز التحكم أو مركز الإشعارات على iOS).

evt حدثُ لمسةٍ اصطناعيّ (synthetic touch event) ذو الشكل التالي:

  • nativeEvent
    • ‎‎changedTouches‎‎: مصفوفة جميع أحداث اللمس التي تغيّرت منذ آخر حدث.
    • ‎‎identifier‎‎: مُعرِّف (ID) اللمسة.
    • ‎‎locationX‎‎: موقع X للّمسة، نسبةً للعنصر.
    • ‎‎locationY‎‎: موقع Y للّمسة، نسبةً للعنصر.
    • ‎‎pageX‎‎: موضع X للّمسة، نسبةً للعنصر الجذر (root element).
    • ‎‎pageY‎‎: موقع Y للّمسة، نسبةً للعنصر الجذر.
    • ‎‎target‎‎: مُعرِّف العقدة (node id) للعنصر الذي يستقبل حدث اللمسة.
    • ‎‎timestamp‎‎: مُعرِّف وقتٍ (time identifier) للمسة، ما يُفيد في حساب السرعة.
    • ‎‎touches‎‎: مصفوفة جميع اللمسات الحالية على الشاشة.

التقاط معالجات ShouldSet

يُستدعَى الحدث ‎‎onStartShouldSetResponder‎‎ والحدث ‎‎onMoveShouldSetResponder‎‎ بنمط فقاعي (bubbling pattern)، حيث تُستدعَى العقدة الأعمق أولاً. هذا يعني أن العنصر الأعمق سوف يصبح المُستجيب عندما تُعيد واجهات متعددة القيمةَ ‎‎true‎‎ لمعالجات ‎‎*ShouldSetResponder‎‎. هذا أمر مرغوب فيه في معظم الحالات، لأنه يتأكد من أن جميع عناصر التحكم والأزرار قابلة للاستخدام.

ومع ذلك، أحيانًا قد يرغب مُكوِّنٌ أبٌ في التّأكد من أنه سيصبح المستجيب. يمكن التعامل مع هذه الحالة عن طريق استخدام مرحلة الالتقاط (capture phase). قبل أن يصعد نظام المستجيب من المكوّن الأعمق إلى أعلى، سيمرّ بمرحلة التقاط، مُطلِقًا ‎‎on*ShouldSetResponderCapture‎‎. لذا، إذا أراد مكونٌ أبٌ منع الطفل من أن يصبح مستجيبًا عند بدء اللمس، فيجب أن يحتوي على معالج ‎‎onStartShouldSetResponderCapture‎‎ يقوم بإرجاع القيمة true.

‎‎View.props.onStartShouldSetResponderCapture: (evt) => true,‎‎
‎‎View.props.onMoveShouldSetResponderCapture: (evt) => true,‎‎

المستجيب PanResponder

لتفسير الإيماءات على مستوًى أعلى (higher-level)، انظر PanResponder.

مصادر