在SwiftUI中为TextField/SecureField添加图片,为占位文本添加填充。

9

我在SwiftUI中创建了一个文本框和安全文本框,但是我不知道如何在它们中添加图像。与旧版Swift相比,SwiftUI的在线文档不多。我还想将(占位符/输入文本)向右移动一个指定的量,例如30个点。我也尝试了将背景颜色从白色更改为红色,但是如您所见,它在我的代码中没有对UI产生任何影响。

注意: 我的代码中已经调用了GeometryReader以及@state变量用于用户名和密码。

我的目标是让它看起来像这样desired outcome,但现在它看起来像这样current/undesired view

            VStack (spacing: deviceSize.size.height * (50/812)) {
                TextField ("Username", text: self.$username)
                    .foregroundColor(.black)//text color when you type
                    .accentColor(.blue)//cursor color
                    .background(Color(.red))//????
                    .textFieldStyle(RoundedBorderTextFieldStyle())
                    .cornerRadius(50)

                // .border(Color.white)
                //.font(.title)

                SecureField ("Password", text: self.$password)
                    .textFieldStyle(RoundedBorderTextFieldStyle())
                    .cornerRadius(50)

            }
            .padding(.init(top: 0, leading: deviceSize.size.width * (38/375), bottom: 0, trailing: deviceSize.size.width * (38/375)))
5个回答

19

最简单的实现方法是将ImageTextField放在一个HStack内,然后给它一个圆角背景。密码字段稍微复杂一些,因为它需要一个额外的Button,并且当你隐藏/显示密码时需要在TextFieldSecureField之间进行切换。以下是我的实现方式:

struct ContentView: View {
    
    @State private var username = ""
    @State private var password = ""
    @State private var showPassword = false
    
    var body: some View {
        ZStack {
            Color.blue
            VStack {
                HStack {
                    Image(systemName: "person")
                        .foregroundColor(.secondary)
                    TextField("Username",
                              text: $username)
                }   .padding()
                    .background(Capsule().fill(Color.white))
                HStack {
                    Image(systemName: "lock")
                        .foregroundColor(.secondary)
                    if showPassword {
                        TextField("Password",
                        text: $password)
                    } else {
                    SecureField("Password",
                              text: $password)
                    }
                    Button(action: { self.showPassword.toggle()}) {
                        
                        Image(systemName: "eye")
                        .foregroundColor(.secondary)
                    }
                }   .padding()
                    .background(Capsule().fill(Color.white))
            }   .padding()
        }
    }
}

生成的用户名和密码字段


1
很棒的答案。请注意图像框架未对齐。给两个图像一个与宽度和高度相同的框架宽度。或者选择使用纵横比。这会使其更加清晰 :-) - Tobias Hesselink
善于观察细节,@TobiasHesselink! - LuLuGaGa
@LuLuGaGa 在文本框左侧的这些图像在我使用 resizable() 方法之前没有显示出来。 - bain
@bain,你是复制粘贴了我的例子还是使用了其他图片? - LuLuGaGa
@LuLuGaGa 我使用了自己的图像并调整了它们的大小,我发现你使用了系统默认图像,这似乎给了你一个更大的图标,但由于某种原因它对我来说没有出现,所以我只好采用我的解决方法。不过现在一切都好了,感谢你的帮助。你让我完成了95%的工作。 - bain
我使用的系统图像更像是字体,因此不需要调整大小。很高兴你解决了这个问题。 - LuLuGaGa

3

我对SwiftUI还非常陌生,但我找到了一个解决方法,希望它不会在未来引起任何问题,否则将是一个很大的教训。如果有人有任何建议,我也会非常感谢!=]

我将TextField和图像嵌入到ZStack中,并将图像放在一个View内并给它一个填充(padding)。

struct FormInputBox: View {

@State private var text: String = ""
@State private var textFieldState: TextFieldState = .empty

private var textFieldType: TextFieldType
private var textViewPlaceholder = ""

init(placeholder: String,
     textFieldType: TextFieldType) {
    self.textViewPlaceholder = placeholder
    self.textFieldType = textFieldType
}

var body: some View {
    ZStack(alignment: Alignment(horizontal: .trailing, vertical: .center), content: {
        TextField(textViewPlaceholder, text: $text)
            .textFieldStyle(MyTextFieldStyle(textFieldState: $textFieldState))
        AnyView(
            Image("tick")
                .resizable()
                .frame(width: 20, height: 20, alignment: .leading)
        )
            .padding(32)
        
    })
}

this is how it looks


1
这是一个非常优雅的解决方案,不需要考虑隐藏/伪装文本字段输入的背景。但是,您不需要将图像包装在AnyView中。谢谢! - Aaron Vegh

1
"

"Introspect"将适合你

"
 Textfield()
    .introspectTextField { textfield in
        textfield.rightViewMode = .unlessEditing
        textfield.rightView = UIImageView(image: UIImage(named: ImageCatalog.error.content))
     }

1

我在iOS开发方面是一个完全的新手。所以我写的代码就像这样。提前道歉,如果有人因为代码的丑陋而感到不适。

struct ContentView: View {

@State private var nameSearch: String = ""
var body: some View {

ZStack {
            RoundedRectangle(cornerRadius: 25)
                .frame(width: 230, height: 30)
                .border(.black, width: 0.2)
                .foregroundColor(.white)
            HStack {
                ZStack {
                    Image(systemName: "magnifyingglass.circle")
                        .foregroundColor(.gray)
                        .frame(width: 10, height: 10, alignment: .leading)
                        .padding(.trailing, 200)
                    TextField( "Search", text: $nameSearch)
                        .frame(width: 180, height: 30)
                        .padding(.leading, 20 )
                }
            }
        }

1
我已经创建了一个可重复使用的SwiftUI文本字段,名为ASTextField,其工作方式类似于UIKit中的textField,您可以添加textField的leftViewrightView并可以处理与它们相关的事件。
您可以在gist找到其实现。
这是您可以使用它的方法:
struct ContentView : View , ASTextFieldDelegate {

   let leftImage = UIImage(systemName: "calendar")
   let rightImage = UIImage(systemName: "eye")
   let rightImage1 = UIImage(systemName: "trash")

   @State var text : String? = "with simple binding"
   @State var text1 : String? = "with closure for right item"
   @State var text2 : String? = "for secure entry"

   var body: some View {
       VStack {
          Spacer()
           ASTextField(text: $text)

          Spacer()

          ASTextField(rightItem: rightImage1, leftItem: leftImage, handleLeftTap: {
            print("right icon tapped.....")
          }, delegate: self, text: $text1)

          Spacer()

          ASTextField(rightItem: rightImage, leftItem: leftImage, isSecuredEntry: true, delegate: self, text: $text2)

          Spacer()

      }
   }
}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接