الميزات المتقدّمة لقلم الشاشة

يوفّر نظاما التشغيل Android وChromeOS مجموعة متنوعة من واجهات برمجة التطبيقات لمساعدتك في إنشاء تطبيقات تقدّم للمستخدمين تجربة استثنائية لقلم الشاشة. تعرض فئة MotionEvent معلومات حول تفاعل قلم الشاشة مع الشاشة، بما في ذلك ضغط قلم الشاشة والاتجاه والإمالة والتمرير ورصد راحة اليد. تحسِّن الرسومات ذات وقت الاستجابة المنخفض ومكتبات توقّعات الحركة العرض على الشاشة بقلم الشاشة لتقدّم تجربة مشابهة للقلم والورق.

MotionEvent

تمثل الفئة MotionEvent تفاعلات المستخدم مع البيانات، مثل موضع وحركة مؤشرات اللمس على الشاشة. بالنسبة إلى الإدخال بقلم الشاشة، يعرض MotionEvent أيضًا بيانات الضغط والاتجاه والإمالة والتمرير.

بيانات الأحداث

للوصول إلى بيانات MotionEvent، يمكنك إضافة معدِّل pointerInput إلى المكوّنات:

@Composable
fun Greeting() {
    Text(
        text = "Hello, Android!", textAlign = TextAlign.Center, style = TextStyle(fontSize = 5.em),
        modifier = Modifier
            .pointerInput(Unit) {
                awaitEachGesture {
                    while (true) {
                        val event = awaitPointerEvent()
                        event.changes.forEach { println(it) }
                    }
                }
            },
    )
}

يوفّر عنصر MotionEvent بيانات تتعلّق بالجوانب التالية لحدث واجهة المستخدم:

  • الإجراءات: التفاعل الجسدي مع الجهاز - لمس الشاشة، وتحريك المؤشر فوق سطح الشاشة، وتمرير مؤشر الماوس فوق سطح الشاشة
  • المؤشرات: معرّفات العناصر التي تتفاعل مع الشاشة، الإصبع وقلم الشاشة والفأرة
  • المحور: نوع البيانات — إحداثيات س وص، والضغط، والإمالة، والاتجاه، والتمرير (المسافة)

المهام

لتنفيذ دعم قلم الشاشة، تحتاج إلى فهم الإجراء الذي يقوم به المستخدم.

توفر MotionEvent مجموعة متنوعة من ثوابت ACTION التي تحدد أحداث الحركة. أهم الإجراءات بالنسبة إلى قلم الشاشة تشمل ما يلي:

الإجراء الوصف
ACTION_DOWN
ACTION_POINTER_DOWN
لقد اتصل المؤشر بالشاشة.
إجراء_نقل يتحرك المؤشر على الشاشة.
ACTION_UP
ACTION_POINTER_UP
لم يعُد المؤشر على اتصال بالشاشة.
إجراء_إلغاء الحالات التي يجب فيها إلغاء مجموعة الحركة السابقة أو الحالية

يمكن لتطبيقك تنفيذ مهام، مثل بدء ضغط جديد عند حدوث ACTION_DOWN، ورسم الحد الخارجي باستخدام ACTION_MOVE,، وإنهاء الحد عند تشغيل ACTION_UP.

تُسمى مجموعة إجراءات MotionEvent خلال الفترة من ACTION_DOWN إلى ACTION_UP لمؤشر معيّن مجموعة الحركة.

المؤشرات

تعتمد معظم الشاشات على اللمس المتعدد، إذ يعيّن النظام مؤشرًا لكل إصبع أو قلم شاشة أو ماوس أو أي كائن تأشير آخر يتفاعل مع الشاشة. يتيح لك مؤشر المؤشر الحصول على معلومات حول المحور لمؤشر معين، مثل موضع الإصبع الأول الذي يلامس الشاشة أو الثاني.

تتراوح فهارس المؤشرات من صفر إلى عدد المؤشرات التي يعرضها MotionEvent#pointerCount() ناقص 1.

ويمكن الوصول إلى قيم المحور الخاصة بالمؤشرات باستخدام الطريقة getAxisValue(axis, pointerIndex). عندما يتم حذف فهرس المؤشر، يعرض النظام قيمة المؤشر الأول، المؤشر صفر (0).

تحتوي كائنات MotionEvent على معلومات عن نوع المؤشر المستخدم. يمكنك الحصول على نوع المؤشر من خلال التكرار عبر فهارس المؤشرات واستدعاء الطريقة getToolType(pointerIndex).

لمزيد من المعلومات حول المؤشرات، يُرجى الاطّلاع على التعامل مع إيماءات اللمس المتعدد.

إدخالات قلم الشاشة

يمكنك الفلترة للوصول إلى إدخالات قلم الشاشة باستخدام TOOL_TYPE_STYLUS:

Kotlin

val isStylus = TOOL_TYPE_STYLUS == event.getToolType(pointerIndex)

Java

boolean isStylus = TOOL_TYPE_STYLUS == event.getToolType(pointerIndex);

يمكن لقلم الشاشة أيضًا الإبلاغ عن أنّه يتم استخدامه كممحاة مع TOOL_TYPE_ERASER:

Kotlin

val isEraser = TOOL_TYPE_ERASER == event.getToolType(pointerIndex)

Java

boolean isEraser = TOOL_TYPE_ERASER == event.getToolType(pointerIndex);

بيانات محور قلم الشاشة

توفّر السمتان ACTION_DOWN وACTION_MOVE بيانات المحور حول قلم الشاشة، أي الإحداثيات x وy والضغط والاتجاه والإمالة والتمرير.

لإتاحة الوصول إلى هذه البيانات، توفر MotionEvent واجهة برمجة التطبيقات getAxisValue(int)، حيث تكون المعلمة هي أي من معرّفات المحور التالية:

Axis القيمة المعروضة هي getAxisValue().
AXIS_X الإحداثي السيني (X) لحدث حركة.
AXIS_Y الإحداثي Y لحدث الحركة.
AXIS_PRESSURE الضغط الذي يتم تنفيذه بواسطة الإصبع أو القلم أو المؤشر الآخر على الشاشة التي تعمل باللمس أو لوحة اللمس بالنسبة إلى الماوس أو كرة التعقب، 1 في حال الضغط على الزر الأساسي، 0 في الحالات الأخرى.
AXIS_ORIENTATION اتجاه الإصبع أو القلم أو أي مؤشر آخر بالنسبة إلى الشاشة التي تعمل باللمس أو لوحة اللمس، وذلك بالنسبة إلى المستوى الرأسي للجهاز
AXIS_TILT زاوية إمالة قلم الشاشة بوحدات الراديان.
AXIS_DISTANCE مسافة مسافة قلم الشاشة عن الشاشة.

على سبيل المثال، تعرض MotionEvent.getAxisValue(AXIS_X) الإحداثي x للمؤشر الأول.

راجِع أيضًا التعامل مع إيماءات اللمس المتعدّد.

الموضع

يمكنك استرداد الإحداثيات x وy للمؤشر باستخدام الطلبات التالية:

قلم شاشة يرسم على الشاشة مع ربط إحداثيات x وy.
الشكل 1. إحداثيات x وy على الشاشة لمؤشر قلم الشاشة.

الضغط

يمكنك استرداد ضغط المؤشر باستخدام MotionEvent#getAxisValue(AXIS_PRESSURE) أو MotionEvent#getPressure() للمؤشر الأول.

قيمة الضغط لشاشات اللمس أو لوحات اللمس هي قيمة بين 0 (بدون ضغط) و1، ولكن يمكن عرض قيم أعلى بناءً على معايرة الشاشة.

خطّ بقلم الشاشة يمثّل سلسلة مستمرة من الضغط المنخفض إلى المرتفع. السكتة الدماغية ضيقة وباهتة على اليسار، مما يشير إلى انخفاض الضغط. يصبح الخط أعرض وأكثر قتامة من اليسار إلى اليمين حتى يصبح أعرض وأغمق على أقصى اليمين، مما يشير إلى أعلى ضغط.
الشكل 2. تمثيل الضغط: ضغط منخفض على اليسار، ضغط مرتفع على اليمين.

الاتجاه

يشير الاتجاه إلى الاتجاه الذي يشير إليه قلم الشاشة.

يمكن استرداد اتجاه المؤشر باستخدام getAxisValue(AXIS_ORIENTATION) أو getOrientation() (للمؤشر الأول).

بالنسبة لقلم الشاشة، يتم عرض الاتجاه كقيمة راديان تتراوح بين 0 وباي (ص) في اتجاه عقارب الساعة أو 0 إلى -pi عكس اتجاه عقارب الساعة.

يمكّنك التوجيه من تنفيذ فرشاة حقيقية. على سبيل المثال، إذا كان قلم الشاشة يمثل فرشاة مسطحة، فسيعتمد عرض الفرشاة المسطحة على اتجاه قلم الشاشة.

الشكل 3. قلم شاشة يشير إلى اليسار بحوالي سالب .57 راديان.

إمالة

تقيس ميزة "الإمالة" ميل قلم الشاشة بالنسبة إلى الشاشة.

تعرض الإمالة الزاوية الموجبة لقلم الشاشة بوحدات الراديان، حيث يكون الصفر عموديًا على الشاشة وباي/2 مسطّحًا على السطح.

يمكن استرداد زاوية الإمالة باستخدام getAxisValue(AXIS_TILT) (بدون اختصار للمؤشر الأول).

يمكن استخدام ميزة الإمالة لإعادة إنتاج المحتوى بأقرب شكل ممكن من الأدوات الواقعية، مثل محاكاة التظليل باستخدام قلم رصاص مائل.

قلم الشاشة يميل نحو 40 درجة من سطح الشاشة.
الشكل 4. قلم الشاشة مائل عند حوالي 785 راديان، أو 45 درجة عن العمودي.

تمرير مؤشر الماوس

يمكن تحديد المسافة بين قلم الشاشة والشاشة باستخدام getAxisValue(AXIS_DISTANCE). تُرجع الطريقة قيمة من 0.0 (التلامس مع الشاشة) إلى قيم أعلى عندما يبتعد قلم الشاشة عن الشاشة. وتعتمد المسافة بين الشاشة وقلم الشاشة على الشركة المصنّعة لكل من الشاشة وقلم الشاشة. نظرًا لأن عمليات التنفيذ يمكن أن تختلف، فلا تعتمد على القيم الدقيقة للحصول على الوظائف الأساسية للتطبيق.

يمكن استخدام التمرير بقلم الشاشة لمعاينة حجم الفرشاة أو الإشارة إلى اختيار زر.

الشكل 5. قلم شاشة يتحرّك فوق شاشة يتفاعل التطبيق على الرغم من أنّ قلم الشاشة لا يلامس سطح الشاشة.

ملاحظة: توفر ميزة Compose تعديلاً تؤثّر في الحالة التفاعلية لعناصر واجهة المستخدم:

  • hoverable: يمكنك ضبط المكوِّن ليكون قابلاً للتمرير عن طريق استخدام أحداث الدخول والخروج من المؤشر.
  • indication: لرسم تأثيرات بصرية لهذا المكوِّن عند حدوث تفاعلات.

رفض راحة اليد والتنقل والإدخالات غير المرغوب فيها

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

نتيجةً لذلك، يجب الاحتفاظ بسجلّ إدخالات المستخدم حتى يمكن إزالة اللمسات غير المرغوب فيها من الشاشة وإعادة عرض إدخالات المستخدم المشروعة.

ACTION_CANCEL وFLAG_CANCELED

إنّ السمتَين ACTION_CANCEL وFLAG_CANCELED، تم تصميمهما لإعلامك بضرورة إلغاء مجموعة MotionEvent السابقة من آخر ACTION_DOWN، ما يتيح لك مثلاً التراجع عن آخر خطوة في تطبيق الرسم لمؤشر معيّن.

إجراء_إلغاء

تمت الإضافة في Android 1.0 (المستوى 1 من واجهة برمجة التطبيقات)

تشير السمة ACTION_CANCEL إلى أنّه يجب إلغاء المجموعة السابقة من أحداث الحركة.

يتم تشغيل ACTION_CANCEL عند رصد أي مما يلي:

  • إيماءات التنقل
  • تمرين رفض راحة اليد

عند تشغيل ACTION_CANCEL، يجب تحديد المؤشر النشط باستخدام getPointerId(getActionIndex()). بعد ذلك، عليك إزالة الحد الخارجي الذي تم إنشاؤه باستخدام هذا المؤشر من سجلّ الإدخال، ثم إعادة عرض المشهد.

FLAG_مُلغى

تمت الإضافة في Android 13 (المستوى 33)

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

يمكنك الوصول إلى قيمة العلامة على النحو التالي:

Kotlin

val cancel = (event.flags and FLAG_CANCELED) == FLAG_CANCELED

Java

boolean cancel = (event.getFlags() & FLAG_CANCELED) == FLAG_CANCELED;

في حال ضبط العلامة، عليك التراجع عن آخر مجموعة MotionEvent من آخر ACTION_DOWN من هذا المؤشر.

مثل ACTION_CANCEL، يمكن العثور على المؤشر باستخدام getPointerId(actionIndex).

الشكل 6. تم إنشاء MotionEvent مجموعة من خلال السكتة الدماغية بقلم الشاشة ولمسة راحة اليد. يتم إلغاء ميزة "لمس راحة اليد" وإعادة عرض الشاشة.

إيماءات ملء الشاشة والحواف إلى الحافة وإيماءات التنقل

إذا كان التطبيق بملء الشاشة وبه عناصر قابلة للتنفيذ بالقرب من الحافة، مثل لوحة الرسم أو تطبيق تدوين الملاحظات، قد يؤدي التمرير سريعًا من أسفل الشاشة لعرض التنقل أو نقل التطبيق إلى الخلفية إلى لمسة غير مرغوب فيها على اللوحة.

الشكل 7. إيماءة التمرير السريع لنقل التطبيق إلى الخلفية

لمنع الإيماءات من تشغيل اللمسات غير المرغوب فيها في تطبيقك، يمكنك الاستفادة من الدمج و ACTION_CANCEL.

راجع أيضًا قسم رفض راحة اليد والتنقل والإدخالات غير المرغوب فيها.

استخدِم طريقة setSystemBarsBehavior() وBEHAVIOR_SHOW_TRANSIENT_BARS_BY_SWIPE من WindowInsetsController لمنع إيماءات التنقّل من التسبُّب في أحداث لمس غير مرغوب فيها:

Kotlin

// Configure the behavior of the hidden system bars.
windowInsetsController.systemBarsBehavior =
    WindowInsetsControllerCompat.BEHAVIOR_SHOW_TRANSIENT_BARS_BY_SWIPE

Java

// Configure the behavior of the hidden system bars.
windowInsetsController.setSystemBarsBehavior(
    WindowInsetsControllerCompat.BEHAVIOR_SHOW_TRANSIENT_BARS_BY_SWIPE
);

لمزيد من المعلومات حول إدارة الإدخالات والإيماءات، راجع:

وقت استجابة سريع

وقت الاستجابة هو الوقت الذي تستغرقه الأجهزة والنظام والتطبيق لمعالجة البيانات التي يُدخلها المستخدم وعرضها.

وقت الاستجابة = معالجة إدخال الأجهزة ونظام التشغيل + معالجة التطبيق + تركيب النظام

  • عرض الأجهزة
يؤدي وقت الاستجابة إلى تأخر الخط المعروض عن موضع قلم الشاشة. تشير الفجوة بين الحد الخارجي وموضع قلم الشاشة إلى وقت الاستجابة.
الشكل 8. يؤدي وقت الاستجابة إلى تأخر الخط المعروض عن موضع قلم الشاشة.

مصدر وقت الاستجابة

  • تسجيل قلم الشاشة باستخدام الشاشة التي تعمل باللمس (الأجهزة): اتصال لاسلكي مبدئي عند اتصال قلم الشاشة ونظام التشغيل ليتم تسجيلهما ومزامنتهما.
  • معدل أخذ عينات اللمس (الأجهزة): عدد المرات في الثانية التي تعمل باللمس للتحقق مما إذا كان مؤشر يلامس السطح، ويتراوح المعدل بين 60 و1000 هرتز.
  • معالجة الإدخال (التطبيق): تطبيق اللون ومؤثرات الرسومات والتحويل على البيانات التي أدخلها المستخدم.
  • عرض الرسومات (نظام التشغيل + الأجهزة): تبديل المخزن المؤقت ومعالجة الأجهزة

رسومات ذات وقت استجابة قصير

تقلّل مكتبة رسومات Jetpack وقت الاستجابة المنخفض من وقت المعالجة بين البيانات التي يُدخلها المستخدم والعرض على الشاشة.

تقلل المكتبة من وقت المعالجة من خلال تجنّب العرض متعدد التخزين المؤقت والاستفادة من أسلوب عرض المخزن المؤقت الأمامي، وهو ما يعني الكتابة مباشرةً على الشاشة.

عرض المخزن المؤقت الأمامي

المخزن المؤقت الأمامي هو الذاكرة التي تستخدمها الشاشة للعرض. إنه أقرب التطبيقات التي يمكن أن ترسم على الشاشة مباشرة. تعمل مكتبة وقت الاستجابة المنخفض على تمكين التطبيقات من العرض مباشرةً على المخزن المؤقت الأمامي. يساعد ذلك في تحسين الأداء من خلال منع تبديل المخزن المؤقت، وهو ما قد يحدث مع العرض العادي للمخزن المؤقت المتعدد أو العرض المزدوج في التخزين المؤقت (الحالة الأكثر شيوعًا).

يكتب التطبيق إلى المخزن المؤقت للشاشة ويقرأ من المخزن المؤقت للشاشة.
الشكل 9. عرض المحتوى في المخزن المؤقت الأمامي
يكتب التطبيق إلى المخزن المؤقت المتعدد الذي يتم تبديله مع المخزن المؤقت للشاشة. يقرأ التطبيق من المخزن المؤقت للشاشة.
الشكل 10. العرض بمخزن مؤقت متعدد

يُعدّ العرض في المخزن المؤقت أسلوبًا رائعًا لعرض مساحة صغيرة من الشاشة، إلا أنّه غير مصمَّم للاستخدام لإعادة تحميل الشاشة بأكملها. باستخدام العرض في المخزن المؤقت الأمامي، يعرض التطبيق المحتوى في مخزن مؤقت تتم القراءة منه على الشاشة. ونتيجةً لذلك، يمكن أن يتم عرض أدوات أو تمزيق (انظر أدناه).

تتوفّر مكتبة وقت الاستجابة السريعة على أجهزة Android 10 (المستوى 29 لواجهة برمجة التطبيقات) والإصدارات الأحدث وعلى أجهزة ChromeOS التي تعمل بالإصدار 10 (المستوى 29 من واجهة برمجة التطبيقات) والإصدارات الأحدث.

التبعيات

توفر مكتبة وقت الاستجابة المنخفض مكونات تنفيذ عرض المخزن المؤقت الأمامي. تتم إضافة المكتبة كمكتبة كملحق في ملف build.gradle الخاص بوحدة التطبيق:

dependencies {
    implementation "androidx.graphics:graphics-core:1.0.0-alpha03"
}

طلبات معاودة الاتصال في GLFrontBufferRenderer

تتضمن مكتبة وقت الاستجابة السريع واجهة GLFrontBufferRenderer.Callback التي تحدّد الطرق التالية:

لا تراعي مكتبة وقت الاستجابة السريعة نوع البيانات التي تستخدمها مع GLFrontBufferRenderer.

ومع ذلك، تعالج المكتبة البيانات على شكل تدفق لمئات من نقاط البيانات، وبالتالي صمّم بياناتك لتحسين استخدام الذاكرة وتخصيصها.

عمليات معاودة الاتصال

لتفعيل عرض عمليات معاودة الاتصال، نفِّذ GLFrontBufferedRenderer.Callback وألغِ onDrawFrontBufferedLayer() وonDrawDoubleBufferedLayer(). يستخدم "GLFrontBufferedRenderer" عمليات معاودة الاتصال لعرض البيانات بأفضل طريقة ممكنة.

Kotlin

val callback = object: GLFrontBufferedRenderer.Callback<DATA_TYPE> {

   override fun onDrawFrontBufferedLayer(
       eglManager: EGLManager,
       bufferInfo: BufferInfo,
       transform: FloatArray,
       param: DATA_TYPE
   ) {
       // OpenGL for front buffer, short, affecting small area of the screen.
   }

   override fun onDrawMultiDoubleBufferedLayer(
       eglManager: EGLManager,
       bufferInfo: BufferInfo,
       transform: FloatArray,
       params: Collection<DATA_TYPE>
   ) {
       // OpenGL full scene rendering.
   }
}

Java

GLFrontBufferedRenderer.Callback<DATA_TYPE> callbacks =
    new GLFrontBufferedRenderer.Callback<DATA_TYPE>() {
        @Override
        public void onDrawFrontBufferedLayer(@NonNull EGLManager eglManager,
            @NonNull BufferInfo bufferInfo,
            @NonNull float[] transform,
            DATA_TYPE data_type) {
                // OpenGL for front buffer, short, affecting small area of the screen.
        }

    @Override
    public void onDrawDoubleBufferedLayer(@NonNull EGLManager eglManager,
        @NonNull BufferInfo bufferInfo,
        @NonNull float[] transform,
        @NonNull Collection<? extends DATA_TYPE> collection) {
            // OpenGL full scene rendering.
    }
};
تعريف مثيل من GLFrontBufferedRenderer

تحضير GLFrontBufferedRenderer من خلال تقديم SurfaceView وعمليات معاودة الاتصال التي أنشأتها سابقًا. يُحسِّن GLFrontBufferedRenderer العرض في المقدمة والتخزين المؤقت المزدوج باستخدام طلبات معاودة الاتصال:

Kotlin

var glFrontBufferRenderer = GLFrontBufferedRenderer<DATA_TYPE>(surfaceView, callbacks)

Java

GLFrontBufferedRenderer<DATA_TYPE> glFrontBufferRenderer =
    new GLFrontBufferedRenderer<DATA_TYPE>(surfaceView, callbacks);
العرض

يبدأ عرض المخزن المؤقت عند استدعاء الطريقة renderFrontBufferedLayer()، التي تؤدي إلى تشغيل معاودة الاتصال onDrawFrontBufferedLayer().

ويتم استئناف العرض بمخزن مؤقت مزدوج عند استدعاء الدالة commit()، التي تؤدي إلى تشغيل معاودة الاتصال onDrawMultiDoubleBufferedLayer().

في المثال التالي، يتم عرض العملية إلى المخزن المؤقت الأمامي (العرض السريع) عندما يبدأ المستخدم في الرسم على الشاشة (ACTION_DOWN) ويحرّك المؤشر حول (ACTION_MOVE). ويتم عرض العملية على المخزن المؤقت المزدوج عندما يخرج المؤشر عن سطح الشاشة (ACTION_UP).

يمكنك استخدام الرمز requestUnbufferedDispatch() للطلب من نظام الإدخال عدم تجميع أحداث الحركة، ولكن بدلاً من ذلك يرسلها فور توفّرها:

Kotlin

when (motionEvent.action) {
   MotionEvent.ACTION_DOWN -> {
       // Deliver input events as soon as they arrive.
       view.requestUnbufferedDispatch(motionEvent)
       // Pointer is in contact with the screen.
       glFrontBufferRenderer.renderFrontBufferedLayer(DATA_TYPE)
   }
   MotionEvent.ACTION_MOVE -> {
       // Pointer is moving.
       glFrontBufferRenderer.renderFrontBufferedLayer(DATA_TYPE)
   }
   MotionEvent.ACTION_UP -> {
       // Pointer is not in contact in the screen.
       glFrontBufferRenderer.commit()
   }
   MotionEvent.CANCEL -> {
       // Cancel front buffer; remove last motion set from the screen.
       glFrontBufferRenderer.cancel()
   }
}

Java

switch (motionEvent.getAction()) {
   case MotionEvent.ACTION_DOWN: {
       // Deliver input events as soon as they arrive.
       surfaceView.requestUnbufferedDispatch(motionEvent);

       // Pointer is in contact with the screen.
       glFrontBufferRenderer.renderFrontBufferedLayer(DATA_TYPE);
   }
   break;
   case MotionEvent.ACTION_MOVE: {
       // Pointer is moving.
       glFrontBufferRenderer.renderFrontBufferedLayer(DATA_TYPE);
   }
   break;
   case MotionEvent.ACTION_UP: {
       // Pointer is not in contact in the screen.
       glFrontBufferRenderer.commit();
   }
   break;
   case MotionEvent.ACTION_CANCEL: {
       // Cancel front buffer; remove last motion set from the screen.
       glFrontBufferRenderer.cancel();
   }
   break;
}

الإجراءات المسموح بها وغير المسموح بها بشأن العرض

الإجراءات التي يُنصح بها

وأجزاء صغيرة من الشاشة، والكتابة اليدوية، والرسم، والرسم.

الإجراءات غير المُوصى بها

التحديث بملء الشاشة، والعرض الشامل، والتكبير/التصغير. يمكن أن يؤدي إلى تمزيق الجهاز.

تمزيق

يحدث التمزيق عند تحديث الشاشة أثناء تعديل المخزن المؤقت للشاشة في الوقت نفسه. يعرض جزء من الشاشة بيانات جديدة، بينما يعرض جزء آخر بيانات قديمة.

عدم محاذاة الأجزاء العلوية والسفلية من صورة Android بسبب حدوث تمزيق أثناء تحديث الشاشة.
الشكل 11. تمزيق أثناء إعادة تحميل الشاشة من أعلى إلى أسفل.

التنبؤ بالحركة

تقلّل مكتبة توقُّعات الحركة في Jetpack عن وقت الاستجابة الملحوظ من خلال تقدير مسار الحد الخارجي عند المستخدم وتوفير نقاط زائفة ومؤقتة للعارض.

تحصل مكتبة توقّعات الحركة على إدخالات المستخدم الحقيقية ككائنات MotionEvent. تحتوي الأجسام على معلومات حول الإحداثيات x وy والضغط والوقت، وهذه المعلومات يستفيد منها مؤشر الحركة للتنبؤ بالأجسام MotionEvent المستقبلية.

عناصر MotionEvent المتوقَّعة هي مجرد تقديرات. يمكن أن تقلّل الأحداث المتوقّعة من وقت الاستجابة الملاحظ، ولكن يجب استبدال البيانات المتوقَّعة ببيانات MotionEvent الفعلية بعد تلقّيها.

تتوفّر مكتبة توقُّع الحركة في الإصدار Android 4.4 (المستوى 19 لواجهة برمجة التطبيقات) والإصدارات الأحدث وعلى أجهزة ChromeOS التي تعمل بالإصدار 9 من Android (المستوى 28 من واجهة برمجة التطبيقات) والإصدارات الأحدث.

يؤدي وقت الاستجابة إلى تأخر الخط المعروض عن موضع قلم الشاشة. يتم ملء الفجوة بين الحد الخارجي وقلم الشاشة بنقاط التنبؤ. الفجوة المتبقية هي وقت الاستجابة الملحوظ.
الشكل 12. يتم تقليل وقت الاستجابة من خلال التنبؤ بالحركة.

التبعيات

توفر مكتبة التنبؤ بالحركة إمكانية تنفيذ التنبؤ. تتم إضافة المكتبة كمكتبة كتبعية في ملف build.gradle الخاص بوحدة التطبيق:

dependencies {
    implementation "androidx.input:input-motionprediction:1.0.0-beta01"
}

التنفيذ

تتضمن مكتبة توقُّع الحركة واجهة MotionEventPredictor التي تحدد الطرق التالية:

  • record(): تخزين عناصر MotionEvent كسجلّ لإجراءات المستخدم
  • predict(): عرض MotionEvent متوقَّع
توضيح مثيل لـ MotionEventPredictor

Kotlin

var motionEventPredictor = MotionEventPredictor.newInstance(view)

Java

MotionEventPredictor motionEventPredictor = MotionEventPredictor.newInstance(surfaceView);
إطعام المتنبئ بالبيانات

Kotlin

motionEventPredictor.record(motionEvent)

Java

motionEventPredictor.record(motionEvent);
التنبؤ

Kotlin

when (motionEvent.action) {
   MotionEvent.ACTION_MOVE -> {
       val predictedMotionEvent = motionEventPredictor?.predict()
       if(predictedMotionEvent != null) {
            // use predicted MotionEvent to inject a new artificial point
       }
   }
}

Java

switch (motionEvent.getAction()) {
   case MotionEvent.ACTION_MOVE: {
       MotionEvent predictedMotionEvent = motionEventPredictor.predict();
       if(predictedMotionEvent != null) {
           // use predicted MotionEvent to inject a new artificial point
       }
   }
   break;
}

الإجراءات المستحسنة والإجراءات غير المستحسنة في توقّع الحركة

الإجراءات التي يُنصح بها

إزالة نقاط التنبؤ عند إضافة نقطة جديدة للتنبؤ.

الإجراءات غير المُوصى بها

ولا تستخدِم نقاط التوقّع للعرض النهائي.

تطبيقات تدوين الملاحظات

يسمح نظام التشغيل ChromeOS لتطبيقك بإدراج بعض إجراءات تدوين الملاحظات.

لتسجيل تطبيق كتطبيق تدوين ملاحظات على ChromeOS، راجِع توافق الإدخال.

لتسجيل تطبيق كتدوين ملاحظات على Android، راجع إنشاء تطبيق تدوين ملاحظات.

قدّم نظام التشغيل Android 14 (المستوى 34 من واجهة برمجة التطبيقات) هدف ACTION_CREATE_NOTE الذي يتيح لتطبيقك بدء نشاط تدوين الملاحظات على شاشة القفل.

التعرّف على الحبر الرقمي باستخدام أدوات تعلُّم الآلة

باستخدام التعرف على الحبر الرقمي في أدوات تعلّم الآلة، يمكن لتطبيقك التعرّف على النص المكتوب بخط اليد على سطح رقمي بمئات اللغات. يمكنك أيضًا تصنيف الرسومات.

توفّر أدوات تعلّم الآلة الفئة Ink.Stroke.Builder لإنشاء عناصر Ink يمكن معالجتها باستخدام نماذج تعلُّم الآلة لتحويل الكتابة بخط اليد إلى نص.

بالإضافة إلى التعرّف على الكتابة بخط اليد، يستطيع النموذج التعرّف على الإيماءات، مثل الحذف والدائرة.

راجع التعرف على الحبر الرقمي لمزيد من المعلومات.

مصادر إضافية

أدلة المطوِّرين

الدروس التطبيقية حول الترميز