จัดการการดำเนินการของแป้นพิมพ์

เมื่อผู้ใช้โฟกัสที่คอมโพเนนต์ข้อความที่แก้ไขได้ เช่น TextField และอุปกรณ์มีแป้นพิมพ์ฮาร์ดแวร์เชื่อมต่ออยู่ ระบบจะจัดการอินพุตทั้งหมด คุณสามารถระบุแป้นพิมพ์ลัดได้โดยการจัดการเหตุการณ์สำคัญ

แป้นพิมพ์ลัดเริ่มต้น

แป้นพิมพ์ลัดต่อไปนี้พร้อมใช้งานทันที

แป้นพิมพ์ลัด การทำงาน Composable ที่รองรับทางลัด
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

การกดแป้นพิมพ์จะส่งเหตุการณ์สำคัญ 2 รายการ เหตุการณ์หนึ่งจะทริกเกอร์เมื่อผู้ใช้กดปุ่ม ส่วนอีกเหตุการณ์จะทริกเกอร์เมื่อปล่อยปุ่ม คุณแยกความแตกต่างของเหตุการณ์สำคัญ 2 รายการได้โดยอ้างอิงแอตทริบิวต์ type ของออบเจ็กต์ KeyEvent

ค่าที่แสดงผลของแลมบ์ดา 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")
}

กิจกรรมการคลิกแป้น Spacebar และ Enter

แป้นเว้นวรรคและแป้น Enter จะทริกเกอร์กิจกรรมการคลิกด้วย ตัวอย่างเช่น ผู้ใช้สามารถสลับ (เล่นหรือหยุดชั่วคราว) การเล่นสื่อด้วยแป้นเว้นวรรคหรือปุ่ม Enter โดยจัดการกิจกรรมการคลิกดังนี้

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

ตัวแก้ไข clickable จะขัดจังหวะเหตุการณ์สำคัญและเรียกใช้ Callback onClick() เมื่อมีการกดแป้นเว้นวรรคหรือแป้น Enter นั่นคือเหตุผลที่ระบบเรียกใช้ฟังก์ชัน togglePausePlay() โดยการกดแป้น Spacebar หรือ 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 ก็ตาม หากต้องการย้ายโฟกัสของแป้นพิมพ์โดยไม่เพิ่มอักขระ Tab ให้จัดการเหตุการณ์สำคัญก่อนที่จะทริกเกอร์การดำเนินการที่เชื่อมโยงกับเหตุการณ์สำคัญ ดังที่แสดงในข้อมูลโค้ด 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 เช่นกัน ระบบจะเรียกใช้ Lambda onPreviewKeyEvent() ในคอมโพเนนต์หลักก่อน จากนั้นจึงเรียกใช้ onPreviewKeyEvent() ในคอมโพเนนต์ย่อย คุณสามารถใช้แป้นพิมพ์ลัดทั้งหน้าจอได้โดยใช้ประโยชน์จากลักษณะการทำงานนี้

แหล่งข้อมูลเพิ่มเติม