Disclaimer: the solution is not suitable for full custom controls. For these cases, you can try to pass the FocusState as binding: let isFieldInFocus: FocusState<Int?>.Binding
In my case, I have wrapped UITextView. In order to set the focus, I only used .focused($isFieldInFocus)
.
Some of the information can be obtained through the property wrapper(@Environment(\.)
), but this trick does not work with focus.
struct ContentView: View {
@FocusState var isFieldInFocus: Bool
@State var text = "Test message"
@State var isDisabled = false
var body: some View {
VStack {
Text("Focus for UITextView")
.font(.headline)
AppTextView(text: $text)
.focused($isFieldInFocus)
.disabled(isDisabled)
.frame(height: 200)
HStack {
Button("Focus") {
isFieldInFocus = true
}
.buttonStyle(.borderedProminent)
Button("Enable/Disable") {
isDisabled.toggle()
}
.buttonStyle(.borderedProminent)
}
}
.padding()
.background(.gray)
}
}
struct ContentView_Previews: PreviewProvider {
static var previews: some View {
ContentView()
}
}
struct AppTextView: UIViewRepresentable {
@Binding var text: String
@Environment(\.isEnabled) var isEnabled: Bool
@Environment(\.isFocused) var isFocused: Bool // doesn't work
func makeCoordinator() -> Coordinator {
Coordinator(self)
}
func makeUIView(context: Context) -> UITextView {
let textView = UITextView()
textView.font = UIFont.preferredFont(forTextStyle: .body)
textView.delegate = context.coordinator
return textView
}
func updateUIView(_ uiView: UITextView, context: Context) {
uiView.text = text
print("isEnabled", isEnabled, "isFocused", isFocused)
}
class Coordinator : NSObject, UITextViewDelegate {
private var parent: AppTextView
init(_ textView: AppTextView) {
self.parent = textView
}
func textViewDidChange(_ textView: UITextView) {
parent.text = textView.text
}
}
}