Kotak penelusuran

Gunakan kotak penelusuran untuk menerapkan fungsi penelusuran. Kotak penelusuran adalah kolom penelusuran persisten yang memungkinkan pengguna memasukkan kata kunci atau frasa untuk menampilkan hasil yang relevan dalam aplikasi Anda, dan direkomendasikan jika penelusuran adalah fokus utama aplikasi Anda.

Dua kotak penelusuran ditampilkan. Kolom di sebelah kiri hanya memiliki kolom teks.
  Kotak penelusuran di sebelah kiri memiliki kolom teks dan saran penelusuran di bawahnya.
Gambar 1. Kotak penelusuran dasar (1) dan kotak penelusuran dengan saran (2).

Platform API

Gunakan composable SearchBar untuk menerapkan kotak penelusuran. Parameter utama untuk composable ini mencakup hal berikut:

  • inputField: Menentukan kolom input kotak penelusuran. Peristiwa ini biasanya menggunakan SearchBarDefaults.InputField, yang memungkinkan penyesuaian:
    • query: Teks kueri yang akan ditampilkan di kolom input.
    • onQueryChange: Lambda untuk menangani perubahan pada string kueri.
  • expanded: Boolean yang menunjukkan apakah kotak penelusuran diperluas untuk menampilkan saran atau hasil yang difilter.
  • onExpandedChange: Lambda untuk menangani perubahan pada status dropdown yang diperluas.

  • content: Konten kotak penelusuran ini untuk menampilkan hasil penelusuran di bawah inputField.

Cuplikan ini menunjukkan implementasi dasar SearchBar dengan saran:

@OptIn(ExperimentalMaterial3Api::class)
@Composable
fun SimpleSearchBar(
    textFieldState: TextFieldState,
    onSearch: (String) -> Unit,
    searchResults: List<String>,
    modifier: Modifier = Modifier
) {
    // Controls expansion state of the search bar
    var expanded by rememberSaveable { mutableStateOf(false) }

    Box(
        modifier
            .fillMaxSize()
            .semantics { isTraversalGroup = true }
    ) {
        SearchBar(
            modifier = Modifier
                .align(Alignment.TopCenter)
                .semantics { traversalIndex = 0f },
            inputField = {
                SearchBarDefaults.InputField(
                    query = textFieldState.text.toString(),
                    onQueryChange = { textFieldState.edit { replace(0, length, it) } },
                    onSearch = {
                        onSearch(textFieldState.text.toString())
                        expanded = false
                    },
                    expanded = expanded,
                    onExpandedChange = { expanded = it },
                    placeholder = { Text("Search") }
                )
            },
            expanded = expanded,
            onExpandedChange = { expanded = it },
        ) {
            // Display search results in a scrollable column
            Column(Modifier.verticalScroll(rememberScrollState())) {
                searchResults.forEach { result ->
                    ListItem(
                        headlineContent = { Text(result) },
                        modifier = Modifier
                            .clickable {
                                textFieldState.edit { replace(0, length, result) }
                                expanded = false
                            }
                            .fillMaxWidth()
                    )
                }
            }
        }
    }
}

Poin-poin penting tentang kode

  • rememberSaveable memastikan bahwa apakah kotak penelusuran diperluas atau ditutup dipertahankan di seluruh perubahan konfigurasi. Fungsi ini menulis nilai yang diingat ke dalam paket savedInstanceState Aktivitas hosting sebelum Aktivitas dihancurkan selama perubahan konfigurasi.
  • Pengubah semantics mengontrol urutan traversal TalkBack.
    • isTraversalGroup ditetapkan untuk Box guna mengelompokkan semua composable turunannya.
    • traversalIndex ditetapkan untuk menentukan urutan TalkBack membaca informasi aksesibilitas dari setiap peer grup. TalkBack membaca informasi aksesibilitas pada peer dengan nilai negatif, seperti -1, sebelum peer dengan nilai positif, seperti 1. Karena nilainya adalah float, Anda dapat menentukan urutan kustom dari banyak peer dengan menetapkan nilai di antara -1.0 dan 1.0 di setiap peer.
  • SearchBar berisi inputField untuk input pengguna dan Column untuk menampilkan saran penelusuran.
    • SearchBarDefaults.InputField membuat kolom input dan menangani perubahan pada kueri pengguna.
    • onQueryChange menangani input teks dan memperbarui status setiap kali teks di kolom input berubah.
    • Status The expanded mengontrol visibilitas daftar saran.
  • searchResults.forEach { result -> … } melakukan iterasi pada daftar searchResults dan membuat ListItem untuk setiap hasil.
    • Saat diklik, ListItem akan memperbarui textFieldState, menciutkan kotak penelusuran, dan mengisi textField dengan hasil penelusuran yang dipilih.

Hasil

Kotak penelusuran ditampilkan dengan huruf &#39;a&#39; yang diketik di dalam kotak. Daftar yang berisi enam saran penelusuran ditampilkan di bawah kotak penelusuran.
Gambar 2. Kotak penelusuran dengan saran ditampilkan.

Kotak penelusuran dengan daftar yang difilter

Contoh ini menunjukkan SearchBar yang memfilter daftar berdasarkan kueri penelusuran pengguna:

@OptIn(ExperimentalMaterial3Api::class)
@Composable
fun CustomizableSearchBar(
    query: String,
    onQueryChange: (String) -> Unit,
    onSearch: (String) -> Unit,
    searchResults: List<String>,
    onResultClick: (String) -> Unit,
    // Customization options
    placeholder: @Composable () -> Unit = { Text("Search") },
    leadingIcon: @Composable (() -> Unit)? = { Icon(Icons.Default.Search, contentDescription = "Search") },
    trailingIcon: @Composable (() -> Unit)? = null,
    supportingContent: (@Composable (String) -> Unit)? = null,
    leadingContent: (@Composable () -> Unit)? = null,
    modifier: Modifier = Modifier
) {
    // Track expanded state of search bar
    var expanded by rememberSaveable { mutableStateOf(false) }

    Box(
        modifier
            .fillMaxSize()
            .semantics { isTraversalGroup = true }
    ) {
        SearchBar(
            modifier = Modifier
                .align(Alignment.TopCenter)
                .semantics { traversalIndex = 0f },
            inputField = {
                // Customizable input field implementation
                SearchBarDefaults.InputField(
                    query = query,
                    onQueryChange = onQueryChange,
                    onSearch = {
                        onSearch(query)
                        expanded = false
                    },
                    expanded = expanded,
                    onExpandedChange = { expanded = it },
                    placeholder = placeholder,
                    leadingIcon = leadingIcon,
                    trailingIcon = trailingIcon
                )
            },
            expanded = expanded,
            onExpandedChange = { expanded = it },
        ) {
            // Show search results in a lazy column for better performance
            LazyColumn {
                items(count = searchResults.size) { index ->
                    val resultText = searchResults[index]
                    ListItem(
                        headlineContent = { Text(resultText) },
                        supportingContent = supportingContent?.let { { it(resultText) } },
                        leadingContent = leadingContent,
                        colors = ListItemDefaults.colors(containerColor = Color.Transparent),
                        modifier = Modifier
                            .clickable {
                                onResultClick(resultText)
                                expanded = false
                            }
                            .fillMaxWidth()
                            .padding(horizontal = 16.dp, vertical = 4.dp)
                    )
                }
            }
        }
    }
}

Poin-poin penting tentang kode

  • Fungsi lambda onQueryChange dipanggil setiap kali pengguna mengetik atau menghapus teks di kotak penelusuran.
  • SearchBarDefaults.InputField berisi leadingIcon, yang menambahkan ikon penelusuran ke awal kolom input, dan trailingIcon, yang menambahkan ikon "opsi lainnya" ke akhir kolom input. Di sini, Anda dapat memberikan opsi pengurutan dan pemfilteran kepada pengguna.
  • onSearch = { … } memanggil lambda onSearch dan menciutkan kotak penelusuran saat penelusuran dikirim.
  • LazyColumn menangani hasil penelusuran yang berpotensi berjumlah besar secara efisien. Fungsi ini melakukan iterasi melalui daftar searchResults dan menampilkan setiap hasil sebagai ListItem.
  • Setiap composable ListItem menampilkan teks item, teks yang menampilkan informasi tambahan, dan ikon bintang sebagai leadingContent item. Dalam contoh ini, opsi untuk memfavoritkan item ditampilkan.
  • Untuk logika pemfilteran, lihat CustomizableSearchBarExample di kode sumber lengkap di GitHub.

Hasil

Kotak penelusuran yang berisi kata-kata penelusuran teks yang diisyaratkan akan ditampilkan. Di bawah kotak penelusuran, daftar saran penelusuran akan ditampilkan, dengan ikon bintang di samping setiap saran.
Gambar 3. Kotak penelusuran dengan saran yang relevan ditampilkan.

Referensi lainnya