How to make simple search bar in SwiftUI

Issue #776

We need to use a custom Binding to trigger onChange as onEditingChanged is only called when the user selects the textField, and onCommit is only called when return or done button on keyboard is tapped.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
import UIKit
import SwiftUI
import EasySwiftUI

struct SearchBar: View {
@Binding
var searchText: String
let onChange: () -> Void
@State
private var showsCancelButton: Bool = false

var body: some View {
return HStack {
textField
cancelButton
}
}

private var searchTextBinding: Binding<String> {
Binding<String>(get: {
searchText
}, set: { newValue in
DispatchQueue.main.async {
searchText = newValue
onChange()
}
})
}

private var textField: some View {
HStack {
Image(systemName: SFSymbol.magnifyingglass.rawValue)

TextField("Search", text: searchTextBinding, onEditingChanged: { isEditing in
withAnimation {
self.showsCancelButton = true
}
onChange()
}, onCommit: {
// No op
})
.foregroundColor(.primary)

Button(action: {
self.searchText = ""
}) {
Image(systemName: SFSymbol.xmarkCircleFill.rawValue)
.opacity(searchText == "" ? 0 : 1)
}
}
.padding(EdgeInsets(top: 8, leading: 6, bottom: 8, trailing: 6))
.foregroundColor(.secondary)
.background(Color(.systemBackground))
.cornerRadius(10.0)
}

@ViewBuilder
private var cancelButton: some View {
if showsCancelButton {
Button("Cancel") {
UIApplication.shared.endEditing(true)
withAnimation {
self.searchText = ""
self.showsCancelButton = false
}
onChange()
}
.foregroundColor(Color(.systemBlue))
}
}
}

extension UIApplication {
func endEditing(_ force: Bool) {
self.windows
.filter{$0.isKeyWindow}
.first?
.endEditing(force)
}
}

Comments