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

旧城冷巷雨未停 提交于 2019-12-19 03:02:28

问题


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

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

回答1:


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:

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()
    }
}



回答2:


To define a custom style, you can use the code below. The Rectangle is used eventually, but inside the custom style, not in your view code. Is this what you want?

Note: Tested on Beta 3

To use your custom initialiser:

struct ContentView : View {
    @State private var username = ""

    var body: some View {
        VStack {

            TextField("Enter text", text: $username)
                .textFieldStyle(.myOwnStyle)

        }.frame(width:300)
    }
}

Your custom initialiser implementation:

public struct MyOwnTextFieldStyle: TextFieldStyle {
    public func _body(configuration: TextField<Self.Label>) -> some View {

        VStack() {
            configuration
                .border(Color.blue, width: 2)
                .foregroundColor(Color.yellow)
            Rectangle()
                .frame(height: 1.0, alignment: .bottom)
                .relativeWidth(1)
                .foregroundColor(Color.red)

        }
    }
}

extension StaticMember where Base : TextFieldStyle {
    public static var myOwnStyle: MyOwnTextFieldStyle.Member {
        StaticMember<MyOwnTextFieldStyle>(MyOwnTextFieldStyle())
    }
}



回答3:


Conforming to the TextFieldStyle protocol

struct BottomLineTextFieldStyle: TextFieldStyle {
    func _body(configuration: TextField<Self._Label>) -> some View {
        VStack() {
            configuration
            Rectangle()
                .frame(height: 0.5, alignment: .bottom)
                .foregroundColor(Color.secondary)
        }
    }
}

Usage:

TextField("Name", text: $presenter.name).textFieldStyle(BottomLineTextFieldStyle())



回答4:


Try it another way

struct ContentView: View {
    @State var name: String = ""
    var body: some View {
        VStack {
            // change frame as per requirement
           TextField("Please enter text", text: $name)
            .frame(width: 300, height: 30, alignment: .center)
            .background(Color.gray.opacity(0.2))
            LineView().frame(width: 300, height: 1.0, alignment: .center)
        }
    }
}

LineView : Create custom wrappers for a UIView

struct LineView: UIViewRepresentable {

    typealias UIViewType = UIView
    func makeUIView(context: UIViewRepresentableContext<LineView>) -> UIView {
        let view = UIView()
        view.backgroundColor = UIColor.lightGray
        return view
    }

    func updateUIView(_ uiView: UIView, context: UIViewRepresentableContext<LineView>) {
    }
}


来源:https://stackoverflow.com/questions/57018760/how-can-i-add-a-bottom-line-on-textfield-swiftui

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!