Как добавить нижнюю строку в TextField (SwiftUI)

Я использую Rectangle() для добавления нижней границы в TextField (SwiftUI)

Но я хочу использовать protocol TextFieldStyle для нижней строки в стиле TextField, например RoundedBorderTextFieldStyle.

Как я могу создать собственный стиль для TextField без использования Rectangle?

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

Как добавить нижнюю строку в TextField (SwiftUI)

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
Стоит ли изучать PHP в 2026-2027 годах?
Стоит ли изучать PHP в 2026-2027 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
25
0
19 856
7
Перейти к ответу Данный вопрос помечен как решенный

Ответы 7

Чтобы определить собственный стиль, вы можете использовать приведенный ниже код. В конечном итоге прямоугольник используется, но внутри пользовательского стиля, а не в коде вашего представления. Это то, что вы хотите?

Примечание. Протестировано на бета-версии 3.

Чтобы использовать собственный инициализатор:

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

    var body: some View {
        VStack {

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

        }.frame(width:300)
    }
}

Ваша собственная реализация инициализатора:

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

Да, это то, что я ищу. Спасибо.

Shawn Baek 14.07.2019 04:53

Больше никаких StaticMember в бета-версии 6. Любая замена?

Bagusflyer 11.09.2019 11:27
Ответ принят как подходящий

Однако решение контики не работает с Бета 6. Поэтому я создал решение, в котором я встраиваю TextField и нарисованную нижнюю строку в новое представление. Вы можете просто скопировать код и использовать его, написав TextFieldWithBottomLine(placeholder: "My placeholder") Используется в представлении, которое выглядит так:

Usage of TextView with bottom 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)
    }
}

Затем я создаю представление, содержащее TextField и HorizontalLine ниже:

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

Чтобы увидеть это в действии, я создал образец представления:

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

Если анимация не будет поддерживаться, мы можем сделать color и heightprivate let.

superarts.org 16.11.2020 01:05

Соответствие протоколу TextFieldStyle

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

Применение:

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

Попробуйте по-другому

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 : создание пользовательских оберток для 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>) {
    }
}

Мое решение состоит в том, чтобы добавить разделитель под текстовое поле:

private let textFieldLength:CGFloat = 200
var body: some View {
     VStack {
         TextField("placeHolder", text: .constant("")).frame(width: textFieldLength, height: 30, alignment: .center)
         Divider().frame(width: textFieldLength, height: 2, alignment: .center)
     }
}

или использовать оверлей

 TextField("", text: .constant(""))
  .frame(width: textFieldLength, height: 30, alignment: .center)
  .multilineTextAlignment(.leading)
  .overlay(Divider().frame(width: textFieldLength, height: 2, alignment: .center), alignment: .bottom)

Я думаю, что решения оверлея чище, чем другие

iGhost 15.07.2020 22:47

Мне нравится простота первого фрагмента. Превосходно.

titusmagnus 27.04.2021 03:47

Делитель

Визуальный элемент, который можно использовать для отделения другого контента.

Вы можете установить color и height

Divider()
 .frame(height: 1)
 .padding(.horizontal, 30)
 .background(Color.red)

struct LoginField: View {

    @State private var email: String = ""
    @State private var password: String = ""

    var body: some View {
        VStack {
            TextField("Email", text: $email)
                .padding(.horizontal, 30).padding(.top, 20)
            Divider()
                .padding(.horizontal, 30)
            TextField("Password", text: $password)
                .padding(.horizontal, 30).padding(.top, 20)
            Divider()
                .padding(.horizontal, 30)
            Spacer()
        }
    }
}

Просто обратите внимание, что вы получаете предложенный платформой интервал, используя .padding(.horizontal) (без указания явной длины)

Ky. 24.06.2020 20:51

Использование .overlay

TextField("[email protected]", text: $email)
        .overlay(VStack{Divider().offset(x: 0, y: 15)})

использование VStack заключается в том, чтобы Divider всегда был горизонтальным.

Просто гениально. Лучший ответ.

Duck 04.01.2021 15:34

почему бы не использовать просто .overlay(Divider(), alignment: .bottom)

Sanath 29.03.2022 13:59

Другие вопросы по теме