SwiftUI自定义SearchBar
8个月前 • 349次点击 • 来自 移动端
标签: SwiftUI
原文链接:How To Create A Search Bar With SwiftUI
文章表述步骤非常清楚,每一步解决什么问题,思路清晰,值得推荐入门学习:
1.需求定义
给myFruits
列表内容添加一个搜索功能
struct ContentView: View {
let myFruits = [
"Apple ?", "Banana ?", "Blueberry ?", "Strawberry ?", "Avocado ?", "Cherries ?", "Mango ?", "Watermelon ?", "Grapes ?", "Lemon ?",
]
var body: some View {
NavigationView {
List {
ForEach(myFruits, id: \.self) { fruit in
Text(fruit)
}
}
.listStyle(GroupedListStyle())
.navigationTitle("MyFruits")
}
}
}
2.添加自定义SearchBar
视图结果如下
首先在Assets
自定义颜色LightGray
更改布局,添加搜索框:
struct ContentView: View {
let myFruits = [
"Apple ?", "Banana ?", "Blueberry ?", "Strawberry ?", "Avocado ?", "Cherries ?", "Mango ?", "Watermelon ?", "Grapes ?", "Lemon ?",
]
@State var searchText = ""
var body: some View {
NavigationView {
VStack(alignment: .leading) {
ZStack {
HStack {
Image(systemName: "magnifyingglass")
TextField("Search ..", text: $searchText)
}.foregroundColor(.gray)
.padding(.leading, 13)
Rectangle()
.foregroundColor(Color("LightGray"))
}
.frame(height: 40)
.cornerRadius(13)
.padding()
List {
ForEach(myFruits, id: \.self) { fruit in
Text(fruit)
}
}
.listStyle(GroupedListStyle())
.navigationTitle("MyFruits")
}
}
}
}
最后效果如下
3.提取SearchBar
稍微有点SwiftUI基础的同学都知道,SearchBar可以作为一个单独的子视图提取出来:
struct SearchBar: View {
@Binding var searchText: String
var body: some View {
ZStack {
Rectangle()
.foregroundColor(Color("LightGray"))
HStack {
Image(systemName: "magnifyingglass")
TextField("Search ..", text: $searchText)
}
.foregroundColor(.gray)
.padding(.leading, 13)
}
.frame(height: 40)
.cornerRadius(13)
.padding()
}
}
此时父视图ContentView
可直接引入SearchBar
:
VStack(alignment: .leading) {
SearchBar(searchText: $searchText)
//...
}
4.搜索状态
父视图ContentView
与子视图SearchBar
需要一个状态码来联动更新:
ContentView
添加:
@State var searching = false
SearchBar(searchText: $searchText, searching: $searching)
SearchBar
添加:
@Binding var searching: Bool
使用searching
属性更新SearchBar
中TextField
编辑状态:
TextField("Search ..", text: $searchText) { startedEditing in
if startedEditing {
withAnimation {
searching = true
}
}
} onCommit: {
withAnimation {
searching = false
}
}
在ContentView
使用.navigationTitle.
实时更新状态,同时使用.toolbar
提供一个取消搜索按钮:
VStack(alignment: .leading) {
//...
.navigationTitle(searching ? "Searching" : "MyFruits")
.toolbar {
if searching {
Button("Cancel") {
searchText = ""
withAnimation {
searching = false
}
}
}
}
}
效果如下:
稍微有点工程经验的同学都应该发现了键盘的隐藏出现了问题,点击取消按钮的同时键盘应该同时隐藏:
添加扩展:
extension UIApplication {
func dismissKeyboard() {
sendAction(#selector(UIResponder.resignFirstResponder), to: nil, from: nil, for: nil)
}
}
响应事件:
Button("Cancel") {
searchText = ""
withAnimation {
searching = false
UIApplication.shared.dismissKeyboard()
}
}
同时,在我们滑动列表的时候(甚至是点击搜索框以外区域),也应该隐藏键盘:
List(myFruits, id: \.self) { fruit in
//...
}
//...
.gesture(DragGesture()
.onChanged({ _ in
UIApplication.shared.dismissKeyboard()
})
)
5.过滤结果
根据搜索框输入内容实时显示结果:
List {
ForEach(myFruits.filter({ (fruit: String) -> Bool in
return fruit.hasPrefix(searchText) || searchText == ""
}), id: \.self) { fruit in
Text(fruit)
}
}