Search code examples
swifttextfieldswiftui

How can I add a bottom line on TextField (SwiftUI)


I use Rectangle() to adding a bottom border on TextField (SwiftUI)

But I want to use protocol TextFieldStyle for a bottom line on TextField Style like an RoundedBorderTextFieldStyle

How can I make a custom style for TextField without using Rectangle?

https://developer.apple.com/documentation/swiftui/staticmember

enter image description here

struct ContentView : View {
    @State private var username = "Text Hellow"
    var body: some View {
        VStack() {
            TextField($username)
                .foregroundColor(Color.yellow)
            Rectangle()
                .frame(height: 1.0, alignment: .bottom)
                .relativeWidth(1)
                .foregroundColor(Color.red)

        }
        .padding()
    }

    func editChanged() {

    }
}

#if DEBUG
struct ContentView_Previews : PreviewProvider {
    static var previews: some View {
        ContentView()
    }
}
#endif

Solution

  • The solution of kontiki does not work with Beta 6, though. So I created a solution where I embed a TextField and a drawn bottom line in a new view. You can just copy the code and use it by writing TextFieldWithBottomLine(placeholder: "My placeholder") Used in a view it looks like:

    Usage of TextView with bottom line

    The first thing I create is a horizontal line:

    import SwiftUI
    
    struct HorizontalLineShape: Shape {
    
        func path(in rect: CGRect) -> Path {
    
            let fill = CGRect(x: 0, y: 0, width: rect.size.width, height: rect.size.height)
            var path = Path()
            path.addRoundedRect(in: fill, cornerSize: CGSize(width: 2, height: 2))
    
            return path
        }
    }
    
    struct HorizontalLine: View {
        private var color: Color? = nil
        private var height: CGFloat = 1.0
    
        init(color: Color, height: CGFloat = 1.0) {
            self.color = color
            self.height = height
        }
    
        var body: some View {
            HorizontalLineShape().fill(self.color!).frame(minWidth: 0, maxWidth: .infinity, minHeight: height, maxHeight: height)
        }
    }
    
    struct HorizontalLine_Previews: PreviewProvider {
        static var previews: some View {
            HorizontalLine(color: .black)
        }
    }
    

    Next I create a view that contains a TextField and the HorizontalLine below:

    import SwiftUI
    
    struct TextFieldWithBottomLine: View {
        @State var text: String = ""
        private var placeholder = ""
        private let lineThickness = CGFloat(2.0)
    
        init(placeholder: String) {
            self.placeholder = placeholder
        }
    
        var body: some View {
            VStack {
             TextField(placeholder, text: $text)
                HorizontalLine(color: .black)
            }.padding(.bottom, lineThickness)
        }
    }
    
    struct TextFieldWithBottomLine_Previews: PreviewProvider {
        static var previews: some View {
            TextFieldWithBottomLine(placeholder: "My placeholder")
        }
    }
    

    To see it in action I created a sample view:

    import SwiftUI
    
    struct SampleView: View {
        @State var text: String = ""
        @ObservedObject var model: LoginModel
    
        init() {
            self.model = LoginModel()
        }
    
        init(model: LoginModel) {
            self.model = model
        }
    
        var body: some View {
            TextFieldWithBottomLine(placeholder: "My placeholder").padding(24)
        }
    
        func initialActions() {
    
        }
    
        func reactOnButtonClick() {
    
        }
    }
    
    struct SampleView_Previews: PreviewProvider {
        static var previews: some View {
            SampleView()
        }
    }