نوار جستجو

از نوار جستجو برای پیاده‌سازی قابلیت جستجو استفاده کنید. نوار جستجو یک فیلد جستجوی دائمی است که به کاربران اجازه می‌دهد یک کلمه کلیدی یا عبارت را وارد کنند تا نتایج مرتبط در برنامه شما نمایش داده شود و زمانی که جستجو تمرکز اصلی برنامه شماست، توصیه می‌شود.

دو نوار جستجو نمایش داده می‌شود. نوار سمت چپ فقط یک فیلد متنی دارد.  نوار جستجوی سمت چپ یک فیلد متنی و یک پیشنهاد جستجو در زیر آن دارد.
شکل 1. یک نوار جستجوی ساده (1) و یک نوار جستجو با پیشنهاد (2).

سطح API

از SearchBar composable برای پیاده‌سازی نوارهای جستجو استفاده کنید. پارامترهای کلیدی این composable شامل موارد زیر است:

  • inputField : فیلد ورودی نوار جستجو را تعریف می‌کند. معمولاً از SearchBarDefaults.InputField استفاده می‌کند که امکان سفارشی‌سازی موارد زیر را فراهم می‌کند:
    • query : متن پرس‌وجویی که قرار است در فیلد ورودی نمایش داده شود.
    • onQueryChange : لامبدا برای مدیریت تغییرات در رشته پرس‌وجو.
  • expanded : یک مقدار بولی که نشان می‌دهد نوار جستجو برای نمایش پیشنهادات یا نتایج فیلتر شده، باز شده است یا خیر.
  • onExpandedChange : لامبدا برای مدیریت تغییرات در حالت باز شده‌ی منوی کشویی.

  • content : محتوای این نوار جستجو برای نمایش نتایج جستجو در زیر inputField .

این قطعه کد، پیاده‌سازی اولیه‌ی SearchBar را به همراه پیشنهادات آن نشان می‌دهد:

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

نکات کلیدی در مورد کد

  • rememberSaveable تضمین می‌کند که چه نوار جستجو باز شود و چه بسته، در طول تغییرات پیکربندی حفظ شود. این تابع مقدار به خاطر سپرده شده را قبل از اینکه Activity در طول تغییر پیکربندی از بین برود، در بسته savedInstanceState Activity میزبان می‌نویسد.
  • اصلاح‌کننده‌ی semantics ، ترتیب پیمایش TalkBack را کنترل می‌کند.
    • isTraversalGroup طوری تنظیم شده است که Box تمام کامپوننت‌های فرزند خود را گروه‌بندی کند.
    • traversalIndex طوری تنظیم شده است که ترتیب خواندن اطلاعات دسترسی از هر گروه peer توسط TalkBack را مشخص کند. TalkBack اطلاعات دسترسی را روی یک peer با مقدار منفی، مانند -1 ، قبل از یک peer با مقدار مثبت، مانند 1 ، می‌خواند. از آنجا که مقدار اعشاری است، می‌توانید با تنظیم مقادیر بین -1.0 و 1.0 در هر peer، ترتیب دلخواهی از چندین peer را مشخص کنید.
  • SearchBar شامل یک inputField برای ورودی کاربر و یک Column برای نمایش پیشنهادات جستجو است.
    • SearchBarDefaults.InputField فیلد ورودی را ایجاد می‌کند و تغییرات در پرس‌وجوی کاربر را مدیریت می‌کند.
    • onQueryChange ورودی متن را مدیریت می‌کند و هر زمان که متن در فیلد ورودی تغییر کند، وضعیت را به‌روزرسانی می‌کند.
    • حالت The expanded میزان نمایش لیست پیشنهادات را کنترل می‌کند.
  • searchResults.forEach { result -> … } در لیست searchResults جستجو می‌کند و برای هر نتیجه یک ListItem ایجاد می‌کند.
    • وقتی روی یک ListItem کلیک می‌شود، textFieldState به‌روزرسانی می‌شود، نوار جستجو را جمع می‌کند و textField با نتیجه جستجوی انتخاب شده پر می‌کند.

نتیجه

یک نوار جستجو با حرف «a» که درون آن تایپ شده است، نمایش داده می‌شود. فهرستی شامل شش پیشنهاد جستجو در زیر نوار جستجو نمایش داده می‌شود.
شکل ۲. نوار جستجو با پیشنهادات نمایش داده شده.

نوار جستجو با لیست فیلتر شده

این مثال یک SearchBar نشان می‌دهد که لیستی را بر اساس عبارت جستجوی کاربر فیلتر می‌کند:

@OptIn(ExperimentalMaterial3Api::class)
@Composable
fun CustomizableSearchBar(
    query: String,
    onQueryChange: (String) -> Unit,
    onSearch: (String) -> Unit,
    searchResults: List<String>,
    onResultClick: (String) -> Unit,
    modifier: Modifier = Modifier,
    // 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,
) {
    // 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)
                    )
                }
            }
        }
    }
}

نکات کلیدی در مورد کد

  • تابع لامبدا onQueryChange هر زمان که کاربر متنی را در نوار جستجو تایپ یا حذف کند، فراخوانی می‌شود.
  • SearchBarDefaults.InputField شامل یک leadingIcon است که یک آیکون جستجو را به ابتدای فیلد ورودی اضافه می‌کند و یک trailingIcon که یک آیکون "گزینه‌های بیشتر" را به انتهای فیلد ورودی اضافه می‌کند. در اینجا می‌توانید گزینه‌های مرتب‌سازی و فیلتر کردن را در اختیار کاربر قرار دهید.
  • onSearch = { … } لامبدا onSearch را فراخوانی می‌کند و هنگام ارسال جستجو، نوار جستجو را جمع می‌کند.
  • یک LazyColumn می‌تواند تعداد زیادی از نتایج جستجو را به طور موثر مدیریت کند. این ستون در لیست searchResults پیمایش می‌کند و هر نتیجه را به عنوان یک ListItem نمایش می‌دهد.
  • هر ListItem composable متن آیتم، متنی که اطلاعات اضافی را نشان می‌دهد و یک آیکون ستاره به عنوان leadingContent آیتم را نشان می‌دهد. در این مثال، گزینه‌ای برای افزودن آیتم به لیست علاقه‌مندی‌ها ارائه شده است.
  • برای منطق فیلترینگ، به CustomizableSearchBarExample در کد منبع کامل در GitHub مراجعه کنید.

نتیجه

یک نوار جستجو حاوی کلمات اشاره‌گر متن جستجو شده در داخل آن نشان داده می‌شود. در زیر نوار جستجو، فهرستی از پیشنهادات جستجو نمایش داده می‌شود که در کنار هر پیشنهاد، یک نماد ستاره وجود دارد.
شکل ۳. نوار جستجو با پیشنهادات مرتبط نمایش داده می‌شود.

منابع اضافی