Menangani tindakan keyboard

Saat pengguna memberikan fokus ke komponen teks yang dapat diedit, seperti TextField, dan perangkat memiliki keyboard hardware terpasang, semua input ditangani oleh sistem. Anda dapat menyediakan pintasan keyboard dengan menangani peristiwa tombol.

Pintasan keyboard default

Pintasan keyboard berikut tersedia secara default.

Pintasan keyboard Tindakan Composable yang mendukung pintasan
Shift+Ctrl+Left arrow/Right arrow Memilih teks ke awal/akhir kata BasicTextField, TextField
Shift+Ctrl+Up arrow/Down arrow Memilih teks ke awal/akhir paragraf BasicTextField, TextField
Shift+Alt+panah atas/panah bawah atau Shift+Meta+panah kiri/panah kanan Memilih teks ke awal/akhir teks BasicTextField, TextField
Shift+Left arrow/Right arrow Memilih karakter BasicTextField, TextField
Ctrl+A Pilih semua BasicTextField, TextField
Ctrl+C/Ctrl+X/Ctrl+V Salin/potong/tempel BasicTextField, TextField
Ctrl+Z/Ctrl+Shift+Z Urungkan/ulangi BasicTextField, TextField
PageDown/PageUp Scroll LazyColumn, pengubah verticalScroll, pengubah scrollable

Peristiwa tombol

Di Compose, Anda dapat menangani penekanan tombol individual dengan pengubah onKeyEvent. Pengubah menerima lambda yang dipanggil saat komponen yang diubah menerima peristiwa tombol. Peristiwa tombol dijelaskan sebagai KeyEvent objek. Anda bisa mendapatkan informasi setiap peristiwa tombol dengan merujuk ke objek dalam lambda yang diteruskan ke pengubah onKeyEvent.

Penekanan tombol mengirimkan dua peristiwa tombol. Satu dipicu saat pengguna menekan tombol; yang lain dipicu saat tombol dilepaskan. Anda dapat membedakan kedua peristiwa tombol dengan merujuk ke atribut type dari objek KeyEvent.

Nilai yang ditampilkan dari lambda onKeyEvent menunjukkan apakah peristiwa tombol ditangani atau tidak. Tampilkan true jika aplikasi Anda menangani peristiwa tombol, yang menghentikan propagasi peristiwa.

Cuplikan berikut menunjukkan cara memanggil fungsi doSomething() saat pengguna melepaskan tombol S pada komponen Box:

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

Tombol pengubah

Objek KeyEvent memiliki atribut berikut yang menunjukkan apakah tombol pengubah ditekan atau tidak:

Berikan deskripsi yang spesifik saat menjelaskan peristiwa tombol yang ditangani aplikasi Anda. Cuplikan berikut memanggil fungsi doSomething() hanya jika pengguna melepaskan tombol S saja. Jika pengguna menekan tombol pengubah apa pun, seperti tombol Shift, aplikasi tidak akan memanggil fungsi tersebut.

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")
}

Peristiwa klik tombol Spasi dan Enter

Tombol Spacebar dan Enter juga memicu peristiwa klik. Misalnya, pengguna dapat mengalihkan (memutar atau menjeda) pemutaran media dengan tombol Spacebar atau Enter dengan menangani peristiwa klik sebagai berikut:

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

Pengubah clickable mencegat peristiwa tombol dan memanggil callback onClick() saat tombol Spacebar atau Enter ditekan. Itulah sebabnya fungsi togglePausePlay() dipanggil dengan menekan tombol Spacebar atau Enter dalam cuplikan.

Peristiwa tombol yang tidak digunakan

Peristiwa tombol yang tidak digunakan dipropagasi dari komponen tempat peristiwa terjadi ke komponen luar yang melampirkan. Dalam contoh di bawah, InnerComponent menggunakan peristiwa tombol saat tombol S dilepaskan, sehingga OuterComponent tidak menerima peristiwa tombol apa pun yang dipicu dengan melepaskan tombol S. Itulah sebabnya fungsi actionB() tidak pernah dipanggil.

Peristiwa tombol lainnya di InnerComponent, seperti melepaskan tombol D, dapat ditangani oleh OuterComponent. Fungsi actionC() dipanggil karena peristiwa tombol untuk melepaskan tombol D dipropagasi ke 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
            }
        }
    )
}

Pengubah onKeyPreviewEvent

Dalam beberapa kasus penggunaan, Anda ingin mencegat peristiwa tombol sebelum memicu tindakan default. Menambahkan pintasan kustom ke TextField adalah salah satu contohnya. Cuplikan berikut memungkinkan pengguna berpindah ke komponen berikutnya yang dapat difokuskan dengan menekan tombol tab key.

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
        }
    }
)

Secara default, komponen TextField menambahkan karakter tab setiap kali pengguna menekan tombol Tab, meskipun peristiwa tombol ditangani dengan pengubah onKeyEvent. Untuk memindahkan fokus keyboard tanpa menambahkan karakter tab apa pun, tangani peristiwa tombol sebelum memicu tindakan yang terkait dengan peristiwa tombol, seperti dalam cuplikan. Lambda onKeyPreviewEvent() mencegat peristiwa tombol dengan menampilkan true.

Komponen induk dapat mencegat peristiwa tombol yang terjadi pada komponen turunannya. Dalam cuplikan berikut, fungsi previewSKey() dipanggil saat pengguna menekan tombol S, bukan memanggil fungsi 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() untuk komponen Box juga tidak dipicu saat pengguna menekan tombol Tab. Lambda onPreviewKeyEvent() dipanggil pada komponen induk terlebih dahulu, lalu onPreviewKeyEvent() di komponen turunan dipanggil. Anda dapat menerapkan pintasan keyboard di seluruh layar dengan memanfaatkan perilaku ini.

Referensi lainnya

  • Keyboard Shortcuts Helper: Layar sistem yang memungkinkan pengguna menelusuri pintasan keyboard yang ditawarkan aplikasi Anda.