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

عندما يركّز المستخدم على مكوّن نص قابل للتعديل، مثل 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
        .onKeyEvent {
            if (
                it.type == KeyEventType.KeyUp &&
                it.key == Key.S
            ) {
                doSomething()
                true
            } else {
                false
            }
        }
        .focusable()
) {
    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 من خلال معالجة أحداث النقر على النحو التالي:

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

يعترض المعدِّل clickable الأحداث الرئيسية ويستدعي معاودة الاتصال onClick() عند الضغط على مفتاح المسافة أو مفتاح Enter لهذا السبب، يتم استدعاء الدالة togglePausePlay() من خلال الضغط على مفتاح المسافة أو مفتاح Enter في المقتطف.

الأحداث الرئيسية غير المستهلكة

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

يمكن أن يعالج OuterComponent الأحداث الرئيسية الأخرى على InnerComponent، مثل رفع الإصبع عن المفتاح D، . يتم استدعاء الدالة 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")
    }
}

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

مراجع إضافية