Search code examples
swiftswiftuiios15

How can I fix disabled text editor focusing bug in SwiftUI


I think there's a bug that disabled text editor is focussed when I get in and out into another tab. I want to totally disable text editors but I don't know how. Seeing is believing.

struct TabViewWithTextEditor: View {
    var body: some View {
        TabView {
            TextEditors()
                .tabItem {
                    Image(systemName: "text.bubble")
                    Text("Text Editor")
                }
            
            AnotherView()
                .tabItem {
                    Image(systemName: "shippingbox")
                    Text("Empty View")
                }
        }
    }
}

struct TextEditors: View {
    @State var textA: String = "Hello World"
    @State var textB: String = "Placeholder"
    @State var enabled: Bool = true
    
    init() {
        UITextView.appearance().backgroundColor = .clear    // To apply background color.
    }
    
    var body: some View {
        VStack {
            Text("Text Editor")
            TextEditor(text: $textA)
                .background(enabled ? .gray : .red)
                .foregroundColor(.black)
                .disabled(!enabled)
            TextEditor(text: $textB)
                .background(enabled ? .yellow : .red)
                .foregroundColor(.black)
                .disabled(!enabled)
            Toggle("Enable Text Editors", isOn: $enabled)
        }
        .padding(30)
    }
}

struct AnotherView: View {
    var body: some View {
        Text("Empty View")
    }
}

And it looks like

Demonstrate the bug


Solution

  • It looks like the issue is due to TextEditor (or UITextView at backend) preserves focus, probably due to a bug.

    Here is safe workaround - remove focus forcefully before disable

    Tested with Xcode 13.4 / iOS 15.5

    @FocusState private var focused: Bool
    
    var isEditing: Binding<Bool> {
        Binding(get: { enabled } , set: {
            if !$0 {
                focused = false      // << here !!
            }
            enabled = $0
        })
    }
    
    // ...
    
    Toggle("Enable Text Editors", isOn: isEditing)