검색창을 사용하여 검색 기능을 구현합니다. 검색창은 사용자가 키워드나 구문을 입력하여 앱 내에서 관련 결과를 표시할 수 있는 영구 검색 입력란이며, 검색이 앱의 주요 초점인 경우에 권장됩니다.
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는 텍스트 입력을 처리하고 입력 필드의 텍스트가 변경될 때마다 상태를 업데이트합니다.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: 검색창