التعامل مع إجراءات لوحة المفاتيح

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

اختصارات لوحة المفاتيح التلقائية

تتوفّر اختصارات لوحة المفاتيح التالية تلقائيًا.

اختصارات لوحة المفاتيح الإجراء العناصر القابلة للتجميع التي تتيح استخدام الاختصار
Shift+Ctrl+سهم لليسار/سهم لليمين تحديد النص إلى بداية/نهاية الكلمة BasicTextField، TextField
Shift+Ctrl+السهم المتّجه للأعلى/السهم المتّجه للأسفل اختيار النص حتى بداية الفقرة أو نهايتها BasicTextField، TextField
Shift+Alt+السهم المتّجه للأعلى/السهم المتّجه للأسفل أو Shift+Meta+السهم المتّجه لليسار/السهم المتّجه لليمين اختيار النص حتى بداية النص أو نهايته BasicTextField، TextField
Shift+السهم المتّجه لليسار/السهم المتّجه لليمين اختيار الأحرف BasicTextField، TextField
Ctrl+A اختيار الكل BasicTextField، TextField
Ctrl+C/Ctrl+X/Ctrl+V النسخ/القص/اللصق BasicTextField، TextField
Ctrl+Z/Ctrl+Shift+Z تراجع/إعادة BasicTextField، TextField
PageDown/PageUp صفحة مواضع التمرير LazyColumn، معدّل verticalScroll، معدّل scrollable

الأحداث المهمة

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

تُرسِل ضغطة مفتاح حدثَين رئيسيَّين. يتم تشغيل أحدهما عندما يضغط المستخدم على المفتاح، ويُشغَّل الآخر عند تحرير المفتاح. يمكنك التمييز بين الحدثَين الرئيسيَين عن طريق الإشارة إلى السمة type لكائن KeyEvent.

تشير القيمة المعروضة للدالة lambda‏ onKeyEvent إلى ما إذا تمّ التعامل مع الحدث الرئيسي أم لا. اعرض true إذا كان تطبيقك يعالج الحدث الرئيسي. ما يوقف نشر الحدث.

يوضّح المقتطف التالي كيفية استدعاء دالة doSomething() عندما يُطلِق المستخدم مفتاح S في المكوّن Box:

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

مفاتيح التعديل

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

يجب أن يكون وصفك للأحداث الرئيسية التي يعالجها تطبيقك دقيقًا. يستدعي المقتطف التالي دالة doSomething() فقط إذا طرح المستخدم مفتاح S فقط. إذا ضغط المستخدم على أي مفتاح تعديل، مثل مفتاح Shift، فلا يستدعي التطبيق الدالة.

Box(
  modifier = Modifier.focusable().onKeyEvent{
     if(
       it.type == KeyEventType.KeyUp &&
       it.key == Key.S &&
       !it.isAltPressed &&
       !it.isCtrlPressed &&
       !it.isMetaPressed &&
       !it.isShiftPressed
     ) {
       doSomething()
       true
     } else {
       false
     }
  }
)  {
    Text("Press S key with a modifier key")
}

مفتاح المسافة ومفتاح Enter

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

MoviePlayer(
   modifier = Modifier.clickable { togglePausePlay() }
)

يعرقل مفتاح التعديل clickable أحداث المفاتيح ويُجري طلبًا للرجوع إلى onClick() عند الضغط على مفتاح مفتاح المسافة أو مفتاح Enter. وهذا هو سبب اسم الدالة togglePausePlay() من خلال الضغط على مفتاح مفتاح المسافة أو Enter في المقتطف.

الأحداث الرئيسية غير المستخدَمة

يتم نشر الأحداث الرئيسية غير المستهلكة من المكوِّن التي وقع فيها الحدث على المكون الخارجي المتضمِّن. في المثال أدناه، تستهلك السمة InnerComponent الأحداث الرئيسية. عند تحرير مفتاح S، وبالتالي لا تتلقّى OuterComponent أي أحداث رئيسية تم بدؤها. من خلال تحرير المفتاح S. لهذا السبب، لا يتم استدعاء الدالة actionB() مطلقًا.

الأحداث الرئيسية الأخرى على InnerComponent، مثل إطلاق المفتاح D، التي يمكن معالجتها من خلال OuterComponent. يتمّ استدعاء الدالة actionC() لأنّ الحدث الرئيسي ل إبقاء مفتاح D مضغوَطًا يتمّ نشره إلى OuterComponent.

OuterComponent(
    modifier = Modifier.onKeyEvent {
        when {
           it.type == KeyEventType.KeyUp && it.key == Key.S -> {
               actionB() // This function is never called.
               true
           }
           it.type == KeyEventType.KeyUp && it.key == Key.D -> {
               actionC()
               true
           }
           else -> false
        }
    }
) {
    InnerComponent(
        modifier = Modifier.onKeyEvent {
            if(it.type == KeyEventType.KeyUp && it.key == Key.S) {
                actionA()
                true
            } else {
                false
            }
        }
    )
}

مُعدِّل onKeyPreviewEvent

في بعض حالات الاستخدام، قد تحتاج إلى اعتراض حدث رئيسي قبل أن يؤدي إلى بدء الإجراء التلقائي. الطريقة المعتادة هي إضافة الاختصارات المخصّصة إلى TextField. يتيح المقتطف التالي للمستخدمين الانتقال إلى المكوِّن التالي القابل للتركيز من خلال الضغط على مفتاح Tab.

val focusManager = LocalFocusManager.current
var textFieldValue by remember { mutableStateOf(TextFieldValue()) }

TextField(
    textFieldValue,
    onValueChange = {
        textFieldValue = it
    },
    modifier = Modifier.onPreviewKeyEvent {
        if (it.type == KeyEventType.KeyUp && it.key == Key.Tab) {
            focusManager.moveFocus(FocusDirection.Next)
            true
        } else {
            false
        }
    }
)

يضيف المكوّن TextField تلقائيًا حرف تبويب في كل مرة يضغط فيها المستخدمون على مفتاح Tab، حتى إذا تم التعامل مع الحدث الرئيسي باستخدام المُعدِّل onKeyEvent. لنقل تركيز لوحة المفاتيح بدون إضافة أي أحرف من علامات التبويب، التعامل مع الحدث الرئيسي قبل تشغيل الإجراءات المرتبطة بالحدث الرئيسي، كما في المقتطف. تعترض دالة lambda onKeyPreviewEvent() الحدث الرئيسي من خلال إرجاع true.

يمكن للمكون الرئيسي اعتراض الحدث الرئيسي الذي يحدث على عناصره الفرعية. في المقتطف التالي، تُسمى الدالة previewSKey() عندما يضغط المستخدمون على مفتاح S، بدلاً من استدعاء الدالة actionForPreview().

Column(
  modifier = Modifier.onPreviewKeyEvent{
    if(it.key == Key.S){
      previewSKey()
      true
    }else{
      false
    }
  }
) {
  Box(
    modifier = Modifier
        .focusable()
        .onPreviewKeyEvent {
            actionForPreview(it)
            false
        }
        .onKeyEvent {
            actionForKeyEvent(it)
            true
        }
  ) {
    Text("Press any key")
  }
}

لا يتم تنشيط دالة onPreviewKeyEvent() lambda لمكوّن Box عند الضغط على مفتاح Tab أيضًا. يتمّ استدعاء دالة onPreviewKeyEvent() lambda في المكوّن الرئيسي أولاً، ثمّ يتمّ استدعاء onPreviewKeyEvent() في المكوّن الفرعي. يمكنك تنفيذ اختصارات لوحة المفاتيح على مستوى الشاشة من خلال استخدام هذا السلوك.

مصادر إضافية