توافق الإدخال على الشاشات الكبيرة

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

  • اختبِر دعم لوحة المفاتيح الأساسية، مثل Ctrl+Z للتراجع، وCtrl+C للنسخ، وCtrl+S للحفظ. يمكنك الاطّلاع على التعامل مع إجراءات لوحة المفاتيح للحصول على قائمة باختصارات لوحة المفاتيح التلقائية.
  • اختبِر إمكانية استخدام لوحة المفاتيح المتقدّمة، مثل التنقّل باستخدام مفتاح Tab ومفاتيح الأسهم، وتأكيد إدخال النص باستخدام مفتاح Enter، والتشغيل والإيقاف المؤقت باستخدام مفتاح المسافة في تطبيقات الموسيقى.
  • اختبِر تفاعلات الماوس الأساسية، بما في ذلك النقر بزر الماوس الأيمن لفتح قائمة السياق، وتغيير الرموز عند تمرير مؤشر الماوس فوقها، وأحداث التمرير باستخدام عجلة الماوس أو لوحة اللمس على المكوّنات المخصّصة.
  • اختبِر أجهزة الإدخال الخاصة بالتطبيق، مثل قلم الشاشة وأذرع التحكّم في الألعاب ووحدات التحكّم في MIDI لتطبيقات الموسيقى.
  • ننصحك بإتاحة استخدام أجهزة الإدخال المتقدّمة التي يمكن أن تجعل التطبيق متميزًا في بيئات أجهزة الكمبيوتر المكتبي، مثل لوحة اللمس كأداة دمج الصوت لتطبيقات DJ، والتقاط الماوس للألعاب، واختصارات لوحة المفاتيح للمستخدمين الذين يركّزون على لوحة المفاتيح.

لوحة المفاتيح

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

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

في العديد من التطبيقات، يتم التعامل مع التنقل باستخدام مفتاح السهم ومفتاح Tab تلقائيًا بواسطة إطار عمل Android. على سبيل المثال، يمكن التركيز على بعض الدوال المركّبة تلقائيًا، مثل Button أو دالة مركّبة تتضمّن المُعدِّل clickable. من المفترض أن يعمل التنقّل باستخدام لوحة المفاتيح بشكل عام بدون أي رمز إضافي. لتفعيل التنقّل باستخدام لوحة المفاتيح للدوال المركّبة المخصّصة التي لا يمكن التركيز عليها تلقائيًا، أضِف المُعدِّل focusable:

var color by remember { mutableStateOf(Green) }
Box(
    Modifier
        .background(color)
        .onFocusChanged { color = if (it.isFocused) Blue else Green }
        .focusable()
) {
    Text("Focusable 1")
}

لمزيد من المعلومات، يُرجى الاطّلاع على جعل دالة مركّبة قابلة للتركيز.

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

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

للتحكّم في سلوك التركيز، أضِف المُعدِّل focusGroup إلى الدالة المركّبة الرئيسية لمجموعة من الدوال المركّبة. ينتقل التركيز إلى المجموعة، ثم عبر المجموعة قبل الانتقال إلى المكوّن التالي الذي يمكن التركيز عليه، على سبيل المثال:

Row {
    Column(Modifier.focusGroup()) {
        Button({}) { Text("Row1 Col1") }
        Button({}) { Text("Row2 Col1") }
        Button({}) { Text("Row3 Col1") }
    }
    Column(Modifier.focusGroup()) {
        Button({}) { Text("Row1 Col2") }
        Button({}) { Text("Row2 Col2") }
        Button({}) { Text("Row3 Col2") }
    }
}

لمزيد من المعلومات، يُرجى الاطّلاع على توفير تنقّل متّسق باستخدام مجموعات التركيز.

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

تذكَّر أنّ دعم لوحة المفاتيح قد يكون ضروريًا للمستخدمين الذين لديهم احتياجات متعلقة بتسهيل الاستخدام.

ضغطات المفاتيح

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

ومن الأمثلة على ذلك تطبيقات المحادثات التي تستخدم مفتاح Enter لإرسال رسالة، وتطبيقات الوسائط التي تبدأ التشغيل وتوقفه باستخدام مفتاح المسافة، والألعاب التي تتحكّم في الحركة باستخدام المفاتيح w وa وs وd.

يمكنك التعامل مع ضغطات المفاتيح الفردية باستخدام المُعدِّل onKeyEvent الذي يقبل دالة lambda التي يتم استدعاؤها عندما يتلقّى المكوّن المُعدَّل حدثًا رئيسيًا. تتيح لك السمة KeyEvent#type تحديد ما إذا كان الحدث هو الضغط على مفتاح (KeyDown) أو تحرير مفتاح (KeyUp):

Box(
    modifier = Modifier.focusable().onKeyEvent {
        if(
            it.type == KeyEventType.KeyUp &&
            it.key == Key.S
        ) {
            doSomething()
            true
        } else {
            false
        }
    }
)  {
    Text("Press S key")
}

بدلاً من ذلك، يمكنك إلغاء دالة الاستدعاء onKeyUp() وإضافة السلوك المتوقّع لكل رمز مفتاح يتم تلقّيه:

kotlin override fun onKeyUp(keyCode: Int, event: KeyEvent): Boolean { return when (keyCode) { KeyEvent.KEYCODE_ENTER -> { sendChatMessage() true } KeyEvent.KEYCODE_SPACE -> { playOrPauseMedia() true } else -> super.onKeyUp(keyCode, event) } }

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

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

الاختصارات

من المتوقّع استخدام اختصارات لوحة المفاتيح الشائعة التي تتضمّن مفاتيح Ctrl وAlt وShift وMeta عند استخدام لوحة مفاتيح خارجية. إذا لم يتضمّن التطبيق اختصارات، قد يشعر المستخدمون بالإحباط. يقدّر المستخدمون المتقدّمون أيضًا الاختصارات للمهام المتكررة الخاصة بالتطبيق. تسهّل الاختصارات استخدام التطبيق وتميّزه عن التطبيقات التي لا تتضمّن اختصارات.

تشمل بعض الاختصارات الشائعة Ctrl+S (حفظ) وCtrl+Z (تراجع) وCtrl+Shift+Z (إعادة). للحصول على قائمة بالاختصارات التلقائية، يُرجى الاطّلاع على التعامل مع إجراءات لوحة المفاتيح.

يحتوي الكائن KeyEvent على السمات التالية التي تشير إلى ما إذا تم الضغط على مفاتيح التعديل:

على سبيل المثال:

Box(
    Modifier.onKeyEvent {
        if (it.isAltPressed && it.key == Key.A) {
            println("Alt + A is pressed")
            true
        } else {
            false
        }
    }
    .focusable()
)

لمزيد من المعلومات، يُرجى الاطّلاع على ما يلي:

قلم الشاشة

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

للوصول إلى عناصر قلم الشاشة MotionEvent، أضِف المُعدِّل pointerInteropFilter إلى مساحة الرسم. نفِّذ فئة ViewModel باستخدام طريقة تعالج أحداث الحركة، ثم مرِّر الطريقة كدالة lambda onTouchEvent للمعدِّل pointerInteropFilter:

@Composable
@OptIn(ExperimentalComposeUiApi::class)
fun DrawArea(modifier: Modifier = Modifier) {
   Canvas(modifier = modifier
       .clipToBounds()
       .pointerInteropFilter {
           viewModel.processMotionEvent(it)
       }

   ) {
       // Drawing code here.
   }
}

يحتوي العنصر MotionEvent على معلومات عن الحدث:

النقاط السابقة

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

تجاهُل لمس راحة اليد

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

يلغي Android أحداث لمس راحة اليد من خلال إرسال MotionEvent. إذا تلقّى تطبيقك ACTION_CANCEL، عليك إلغاء الإيماءة. إذا تلقّى تطبيقك ACTION_POINTER_UP، تحقَّق مما إذا تم ضبط FLAG_CANCELED. إذا كان الأمر كذلك، فقم بإلغاء الإيماءة.

لا تتحقّق من FLAG_CANCELED فقط. في الإصدار 13 من نظام التشغيل Android (المستوى 33 لواجهة برمجة التطبيقات) والإصدارات الأحدث، يضبط النظام FLAG_CANCELED لأحداث ACTION_CANCEL، ولكنّه لا يضبط العلامة في الإصدارات الأقدم من Android.

Android 12

في الإصدار Android 12 (المستوى 32 لواجهة برمجة التطبيقات) والإصدارات الأقدم، لا يمكن رصد رفض راحة اليد إلا لأحداث اللمس بمؤشر واحد. إذا كانت اللمسة براحة اليد هي المؤشر الوحيد، يلغي النظام الحدث من خلال ضبط ACTION_CANCEL على عنصر حدث الحركة. إذا كانت هناك مؤشرات أخرى لأسفل، يضبط النظام ACTION_POINTER_UP، وهو غير كافٍ لرصد رفض راحة اليد.

Android 13

في الإصدار 13 من نظام التشغيل Android (المستوى 33 لواجهة برمجة التطبيقات) والإصدارات الأحدث، إذا كانت لمسة راحة اليد هي المؤشر الوحيد، يلغي النظام الحدث من خلال ضبط ACTION_CANCEL وFLAG_CANCELED على عنصر حدث الحركة. إذا كانت المؤشرات الأخرى لأسفل، يضبط النظام ACTION_POINTER_UP وFLAG_CANCELED.

عندما يتلقّى تطبيقك حدث حركة باستخدام ACTION_POINTER_UP، تحقَّق من FLAG_CANCELED لتحديد ما إذا كان الحدث يشير إلى رفض راحة اليد (أو إلغاء حدث آخر).

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

يحتوي نظام التشغيل ChromeOS على نية خاصة تعرض تطبيقات تدوين الملاحظات المسجَّلة للمستخدمين. لتسجيل تطبيق كتطبيق لتدوين الملاحظات، أضِف ما يلي إلى بيان التطبيق:

<intent-filter>
    <action android:name="org.chromium.arc.intent.action.CREATE_NOTE" />
    <category android:name="android.intent.category.DEFAULT" />
</intent-filter>

عند تسجيل تطبيق في النظام، يمكن للمستخدم اختياره كتطبيق تدوين الملاحظات التلقائي. وعند طلب ملاحظة جديدة، يجب أن ينشئ التطبيق ملاحظة فارغة جاهزة للإدخال باستخدام قلم الشاشة. عندما يريد المستخدم إضافة تعليقات توضيحية إلى صورة (مثل لقطة شاشة أو صورة تم تنزيلها)، يتم تشغيل التطبيق باستخدام ClipData الذي يحتوي على عنصر واحد أو أكثر مع معرّفات موارد منتظمة (URI) من النوع content://. يجب أن ينشئ التطبيق ملاحظة تستخدم الصورة الأولى المرفقة كصورة خلفية، وأن يدخل في وضع يتيح للمستخدم الرسم على الشاشة باستخدام قلم الشاشة.

اختبار أهداف تدوين الملاحظات بدون قلم شاشة

لاختبار ما إذا كان التطبيق يستجيب بشكل صحيح لطلبات تدوين الملاحظات بدون قلم شاشة نشط، استخدِم الطريقة التالية لعرض خيارات تدوين الملاحظات على ChromeOS:

  1. التبديل إلى وضع مطوِّر البرامج وجعل الجهاز قابلاً للكتابة
  2. اضغط على Ctrl+Alt+F2 لفتح نافذة Terminal
  3. نفِّذ الأمر sudo vi /etc/chrome_dev.conf
  4. اضغط على i لتعديل الملف وإضافة --ash-enable-palette إلى سطر جديد في نهاية الملف
  5. احفظ الملف بالضغط على Esc ثم كتابة : وw وq والضغط على Enter
  6. اضغط على Ctrl+Alt+F1 للعودة إلى واجهة مستخدم ChromeOS العادية
  7. تسجيل الخروج ثم تسجيل الدخول مرة أخرى

من المفترض أن تظهر الآن قائمة قلم الشاشة على الرف:

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

إتاحة استخدام الماوس ولوحة اللمس

تحتاج معظم التطبيقات بشكل عام إلى التعامل مع ثلاثة أحداث فقط تركّز على الشاشة الكبيرة: النقر بزر الماوس الأيمن وتمرير مؤشر الماوس والسحب والإفلات.

النقر بزر الماوس الأيمن

يجب أن تتفاعل أيضًا أحداث النقر بزر الماوس الأيمن مع أي إجراءات تؤدي إلى عرض قائمة سياق في التطبيق، مثل النقر مع الاستمرار على عنصر في القائمة.

للتعامل مع الأحداث الناتجة عن النقر بزر الماوس الأيمن، يجب أن تسجّل التطبيقات View.OnContextClickListener:

Box(modifier = Modifier.fillMaxSize()) {
    AndroidView(
        modifier = Modifier.fillMaxSize(),
        factory = { context ->
            val rootView = FrameLayout(context)
            val onContextClickListener =
                View.OnContextClickListener { view ->
                    showContextMenu()
                    true
                }
            rootView.setOnContextClickListener(onContextClickListener)
            rootView
        },
    )
}

للحصول على تفاصيل حول إنشاء قوائم السياق، يُرجى الاطّلاع على إنشاء قائمة سياق.

التمرير

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

عدد المشاهدات:

المثالان الأكثر شيوعًا على ذلك هما:

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

السحب والإفلات

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

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

لإضافة ميزة السحب والإفلات، يُرجى الاطّلاع على السحب والإفلات ، وإلقاء نظرة على منشور المدوّنة Android على ChromeOS — تنفيذ ميزة السحب والإفلات.

اعتبارات خاصة بنظام التشغيل ChromeOS

  • يُرجى تذكُّر طلب الإذن باستخدام requestDragAndDropPermissions() للوصول إلى العناصر التي تم سحبها من خارج التطبيق
  • يجب أن يتضمّن العنصر العلامة View.DRAG_FLAG_GLOBAL ليتم سحبه إلى تطبيقات أخرى

    يُرجى الاطّلاع على بدء حدث سحب

التوافق مع المؤشرات المتقدّمة

على التطبيقات التي تتعامل بشكل متقدّم مع إدخالات الماوس ولوحة اللمس تنفيذ معدِّل pointerInput للحصول على PointerEvent:

@Composable
private fun LogPointerEvents(filter: PointerEventType? = null) {
    var log by remember { mutableStateOf("") }
    Column {
        Text(log)
        Box(
            Modifier
                .size(100.dp)
                .background(Color.Red)
                .pointerInput(filter) {
                    awaitPointerEventScope {
                        while (true) {
                            val event = awaitPointerEvent()
                            // handle pointer event
                            if (filter == null || event.type == filter) {
                                log = "${event.type}, ${event.changes.first().position}"
                            }
                        }
                    }
                }
        )
    }
}

افحص العنصر PointerEvent لتحديد ما يلي:

أذرع التحكّم في الألعاب

تتيح بعض أجهزة Android ذات الشاشات الكبيرة استخدام ما يصل إلى أربعة أذرع تحكّم في الألعاب. استخدِم واجهات برمجة التطبيقات العادية لذراع التحكّم في الألعاب على Android للتعامل مع أذرع التحكّم في الألعاب (راجِع التوافق مع أذرع التحكّم في الألعاب).

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

وضع ترجمة الإدخال

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

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

<uses-feature
    android:name="android.hardware.type.pc"
    android:required="false" />

مراجع إضافية