J'utilise Rectangle()
pour ajouter une bordure inférieure sur TextField (SwiftUI)
Mais je veux utiliser protocol TextFieldStyle
pour une ligne de fond sur le style TextField comme un RoundedBorderTextFieldStyle
Comment créer un style personnalisé pour TextField sans utiliser 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
Cependant, la solution de kontiki ne fonctionne pas avec Beta 6 . J'ai donc créé une solution où j'intègre un TextField et une ligne de fond dessinée dans une nouvelle vue. Vous pouvez simplement copier le code et l'utiliser en écrivant TextFieldWithBottomLine(placeholder: "My placeholder")
Utilisé dans une vue, il ressemble à:
La première chose que je crée est une ligne horizontale:
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)
}
}
Ensuite, je crée une vue qui contient un TextField et la HorizontalLine ci-dessous:
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")
}
}
Pour le voir en action, j'ai créé un exemple de vue:
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()
}
}
Pour définir un style personnalisé, vous pouvez utiliser le code ci-dessous. Le rectangle est finalement utilisé, mais à l'intérieur du style personnalisé, pas dans votre code de vue. c'est ce que tu veux?
Remarque: testé sur Beta
Pour utiliser votre initialiseur personnalisé:
struct ContentView : View {
@State private var username = ""
var body: some View {
VStack {
TextField("Enter text", text: $username)
.textFieldStyle(.myOwnStyle)
}.frame(width:300)
}
}
Votre implémentation d'initialisation personnalisée:
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())
}
}
Diviseur
Un élément visuel qui peut être utilisé pour séparer d'autres contenus.
Vous pouvez définir color
et 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()
}
}
}
Conforme au protocole TextFieldStyle
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())
Essayez-le d'une autre manière
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: créer des wrappers personnalisés pour un 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>) {
}
}
Ma solution est d'ajouter un séparateur sous le champ de texte:
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)
}
}
ou utilisez la superposition
TextField("", text: .constant(""))
.frame(width: textFieldLength, height: 30, alignment: .center)
.multilineTextAlignment(.leading)
.overlay(Divider().frame(width: textFieldLength, height: 2, alignment: .center), alignment: .bottom)