베이킹 앱을 구현하기 위해 현재 사용자가 가지고 있는 재료를 선택하려고 한다.
기존에는 list 형태로 나열된 재료를 일일이 선택하게끔 구현하였지만 비효율적이라고 생각하여 사용자가 가지고 있는 재료를 검색하여 선택하게끔 구현할 것이다.
그러기 위해서는, 재료를 검색할 때 자동완성 기능이 필요할 것이므로 이에 대해 작성한다.
검색을 하려면 당연히 TextField
가 필요하다.
이 TextField는 무언가 입력되었을 때 X 아이콘이 나타나고 이 아이콘을 클릭하면 입력된 내용이 사라진다.
import SwiftUI
struct ContentView: View {
@State var searchText = ""
@State var isSearching = false // 무언가 입력되었는지 판단하기 위함
var body: some View {
ScrollView {
// MARK: - 텍스트 필드 구현
HStack {
TextField("텍스트를 입력하세요.", text: $searchText)
.padding(.horizontal, 24)
}
.padding()
.background(Color(.systemGray5))
.cornerRadius(5)
.padding(.horizontal)
.overlay(
HStack {
Image(systemName: "magnifyingglass")
Spacer()
if isSearching { // 무언가 입력되었다면
Button(action: {
searchText = "" // 텍스트필드에 있는 내용을 없앤다.
}, label: {
Image(systemName: "xmark.circle.fill")
.padding(.vertical)
})
}
}
.padding(.horizontal, 32)
.foregroundColor(.gray)
)
.onTapGesture {
isSearching.toggle()
}
}
}
}
struct ContentView_Previews: PreviewProvider {
static var previews: some View {
ContentView()
}
}
각 원소가 재료인 문자열 배열을 선언한다.
ForEach
로 배열에 있는 원소를 뿌리면 되는데 고차함수인 filter
를 사용하여 search field에 있는 문자열을 포함하는 원소에 대해서만 뿌리면 된다.
var ingredients: [String] = ["박력분", "강력분", "중력분", "블루베리", "바나나", "딸기", "소금", "설탕"]
.
.
.
// MARK: - 자동완성 구현
ForEach(ingredients.filter({$0.contains(searchText) || searchText.isEmpty}), id: \.self) { data in
HStack {
Text(data)
Spacer()
}
.padding()
Divider()
.background(Color(.systemGray4))
}
.
.
.
사용자가 가지고 있는 재료를 선택했다면, 지금까지 무엇을 선택했는지 알 수 있어야 하고 잘못 선택했다면 삭제할 수 있어야 한다.
그러기 위해서는 @State
속성을 사용하여 선택된 재료를 담는 배열을 선언한다. 해당 프로퍼티가 변경되면 View를 다시 랜더링하므로 항상 최신값을 가진다.
@State var selectedIngredients: [String] = []
let columns = [GridItem(.adaptive(minimum: 100))]
.
.
.
// MARK: - 선택한 재료 확인
ScrollView {
LazyVGrid(columns: columns, spacing: 20) {
ForEach(selectedIngredients, id: \.self) {data in
Button {
if let firstIndex = selectedIngredients.firstIndex(of: data) {
selectedIngredients.remove(at: firstIndex)
}
} label: {
HStack {
Text("\(data)")
Image(systemName: "xmark.circle.fill")
}
.frame(width: 100)
.padding(.vertical, 5)
.foregroundColor(.black)
.background(Color(.systemGray4))
.cornerRadius(12)
}
}
}
}
.frame(height: 50)