نوار جستجو

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

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

سطح میانای برنامه‌سازی کاربردی

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

  • 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 تضمین می‌کند که وضعیت نوار جستجو (ازهم بازشده یا جمع‌شده) درطول تغییرات پیکربندی حفظ شود. این مقدار به‌یادمانده را قبل‌از اینکه «فعالیت» درطول تغییر پیکربندی ازبین برود، در بسته savedInstanceState «فعالیت» میزبان می‌نویسد.
  • توصیف‌گر semantics ترتیب پیمایش TalkBack را کنترل می‌کند.
    • ‫isTraversalGroup برای Box تنظیم شده است تا همه عناصر ترکیبی فرزندش را گروه‌بندی کند.
    • traversalIndex تنظیم شده است تا ترتیب خواندن اطلاعات دسترس‌پذیری از هر همتای گروه را مشخص کند. ‫TalkBack اطلاعات دسترس‌پذیری را در همتایی با مقدار منفی، مثل -1، قبل‌از همتایی با مقدار مثبت، مثل 1، می‌خواند. چون مقدار شناور است، می‌توانید با تنظیم مقادیر بین -1.0 و 1.0 در هر همتا، ترتیب سفارشی بسیاری از همتایان را مشخص کنید.
  • SearchBar حاوی inputField برای درونداد کاربر و Column برای نمایش پیشنهادهای جستجو است.
    • SearchBarDefaults.InputField فیلد ورودی را ایجاد می‌کند و تغییرات پرسمان کاربر را مدیریت می‌کند.
    • onQueryChange ورودی نوشتاری را مدیریت می‌کند و هرگاه نوشتار در فیلد ورودی تغییر کند، وضعیت را به‌روز می‌کند.
    • وضعیت 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 قابل‌ساخت نوشتار مورد، نوشتار نشان‌دهنده اطلاعات اضافی، و نماد ستاره را به‌عنوان leadingContent مورد نشان می‌دهد. در این مثال، گزینه‌ای برای افزودن مورد به موارد دلخواه ارائه می‌شود.
  • برای منطق فیلتر کردن، CustomizableSearchBarExample را در کد منبع کامل در GitHub ببینید.

نتیجه

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

منابع بیشتر