검색창을 사용하여 검색 기능을 구현합니다. 검색창은 사용자가 키워드나 문구를 입력하여 앱 내에서 관련 결과를 표시할 수 있는 지속적인 검색 필드이며, 검색이 앱의 기본 초점인 경우에 권장됩니다.
API 노출 영역
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은 검색창이 확장되었는지 축소되었는지가 구성 변경 간에 유지되도록 합니다. 구성 변경 중에 Activity가 소멸되기 전에 기억된 값을 호스팅 Activity의savedInstanceState번들에 씁니다.semantics수정자는 TalkBack 탐색 순서를 제어합니다.isTraversalGroup은 모든 하위 컴포저블을 그룹화하기 위해Box에 설정됩니다.traversalIndex는 TalkBack이 각 그룹 피어에서 접근성 정보를 읽는 순서를 지정하도록 설정됩니다. TalkBack은1과 같은 양수 값을 갖는 피어보다-1과 같은 음수 값을 갖는 피어의 접근성 정보를 먼저 읽습니다. 값은 부동 소수점이므로 각 피어에서-1.0와1.0사이의 값을 설정하여 여러 피어의 맞춤 순서를 지정할 수 있습니다.
SearchBar에는 사용자 입력을 위한inputField와 검색 추천을 표시하기 위한Column이 포함되어 있습니다.SearchBarDefaults.InputField는 입력 필드를 만들고 사용자 쿼리의 변경사항을 처리합니다.onQueryChange는 텍스트 입력을 처리하고 입력 필드의 텍스트가 변경될 때마다 상태를 업데이트합니다.The expanded상태는 추천 목록의 공개 상태를 제어합니다.
searchResults.forEach { result -> … }는searchResults목록을 반복하고 각 결과에 대해ListItem를 만듭니다.ListItem를 클릭하면textFieldState가 업데이트되고 검색창이 축소되며textField가 선택한 검색 결과로 채워집니다.
결과
필터링된 목록이 있는 검색창
다음 예는 사용자의 검색어에 따라 목록을 필터링하는 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로 표시합니다. 이 예에서는 항목을 즐겨찾기에 추가하는 옵션이 표시됩니다. - 필터링 로직은 GitHub의 전체 소스 코드에서
CustomizableSearchBarExample를 참고하세요.
결과

추가 리소스
- Material Design: 검색창