问题描述
要匹配样式指南,我必须向文本字段添加字距调整,包括占位符和值本身.
To match a Styleguide I have to add kerning to a textfield, both placeholder and value itself.
使用 UIKit 我能够做到这一点:
With UIKit I was able to do so with:
class MyTextField: UITextField {
override func awakeFromNib() {
super.awakeFromNib()
// ...
self.attributedPlaceholder = NSAttributedString(string: self.placeholder ?? "", attributes: [
//...
NSAttributedString.Key.kern: 0.3
])
self.attributedText = NSAttributedString(string: "", attributes: [
// ...
NSAttributedString.Key.kern: 0.3
])
}
}
在 SwiftUI 中,我发现我可以像这样对 Text
元素应用字距调整效果:
In SwiftUI, I could figure out that I could apply a kerning effect to a Text
element like so:
Text("My label with kerning")
.kerning(0.7)
不幸的是,我找不到将字距调整样式应用于 TextField 的值和占位符的方法.关于这个有什么想法吗?提前致谢
Unfortunately, I could not find a way to apply a kerning style to neither a TextField's value nor placeholder. Any ideas on this one? Thanks in advance
推荐答案
有一个关于 HackingwithSwift 展示了如何实现 UITextView.它可以很容易地适应 UITextField.
There is a simple tutorial on HackingwithSwift that shows how to implement a UITextView. It can easily be adapted for UITextField.
这是一个快速示例,展示了如何为您使用 UIViewRepresentable
UITextField
.在文本和占位符上设置字距调整.
Here is a quick example showing how to use UIViewRepresentable
for you UITextField
. Setting the kerning on both the text and the placeholder.
struct ContentView: View {
@State var text = ""
var body: some View {
MyTextField(text: $text, placeholder: "Placeholder")
}
}
struct MyTextField: UIViewRepresentable {
@Binding var text: String
var placeholder: String
func makeUIView(context: Context) -> UITextField {
return UITextField()
}
func updateUIView(_ uiView: UITextField, context: Context) {
uiView.attributedPlaceholder = NSAttributedString(string: self.placeholder, attributes: [
NSAttributedString.Key.kern: 0.3
])
uiView.attributedText = NSAttributedString(string: self.text, attributes: [
NSAttributedString.Key.kern: 0.3
])
}
}
更新
以上不适用于在 attributedText 上设置字距调整.借鉴 Costantino Pistagna 在他的中篇文章中所做的出色工作,我们需要多做一点工作.
Update
The above doesn't work for setting the kerning on the attributedText. Borrowing from the fantastic work done by Costantino Pistagna in his medium article we need to do a little more work.
首先,我们需要创建一个封装的 UITextField
版本,允许我们访问委托方法.
Firstly we need to create a wrapped version of the UITextField
that allows us access to the delegate methods.
class WrappableTextField: UITextField, UITextFieldDelegate {
var textFieldChangedHandler: ((String)->Void)?
var onCommitHandler: (()->Void)?
func textFieldShouldReturn(_ textField: UITextField) -> Bool {
if let nextField = textField.superview?.superview?.viewWithTag(textField.tag + 1) as? UITextField {
nextField.becomeFirstResponder()
} else {
textField.resignFirstResponder()
}
return false
}
func textField(_ textField: UITextField, shouldChangeCharactersIn range: NSRange, replacementString string: String) -> Bool {
if let currentValue = textField.text as NSString? {
let proposedValue = currentValue.replacingCharacters(in: range, with: string)
print(proposedValue)
self.attributedText = NSAttributedString(string: currentValue as String, attributes: [
NSAttributedString.Key.kern: 10
])
textFieldChangedHandler?(proposedValue as String)
}
return true
}
func textFieldDidEndEditing(_ textField: UITextField) {
onCommitHandler?()
}
}
由于每次文本更改时都会调用 shouldChangeCharactersIn
委托方法,我们应该使用它来更新 attributedText
值.我首先尝试使用 proposedVale
但它会使字符加倍,如果我们使用 currentValue
As the shouldChangeCharactersIn
delegate method will get called every time the text changes, we should use that to update the attributedText
value. I tried using first the proposedVale
but it would double up the characters, it works as expected if we use the currentValue
现在我们可以在 UIViewRepresentable
中使用 WrappedTextField
.
Now we can use the WrappedTextField
in the UIViewRepresentable
.
struct SATextField: UIViewRepresentable {
private let tmpView = WrappableTextField()
//var exposed to SwiftUI object init
var tag:Int = 0
var placeholder:String?
var changeHandler:((String)->Void)?
var onCommitHandler:(()->Void)?
func makeUIView(context: UIViewRepresentableContext<SATextField>) -> WrappableTextField {
tmpView.tag = tag
tmpView.delegate = tmpView
tmpView.placeholder = placeholder
tmpView.attributedPlaceholder = NSAttributedString(string: self.placeholder ?? "", attributes: [
NSAttributedString.Key.kern: 10
])
tmpView.onCommitHandler = onCommitHandler
tmpView.textFieldChangedHandler = changeHandler
return tmpView
}
func updateUIView(_ uiView: WrappableTextField, context: UIViewRepresentableContext<SATextField>) {
uiView.setContentHuggingPriority(.defaultHigh, for: .vertical)
uiView.setContentHuggingPriority(.defaultLow, for: .horizontal)
}
}
我们在 makeUIView
中为占位符设置了属性文本.占位符文本没有被更新,所以我们不需要担心改变它.
We set the attributed text for the placeholder in the makeUIView
. The placeholder text is not being updated so we don't need to worry about changing that.
这是我们如何使用它:
struct ContentView: View {
@State var text = ""
var body: some View {
SATextField(tag: 0, placeholder: "Placeholder", changeHandler: { (newText) in
self.text = newText
}) {
// do something when the editing of this textfield ends
}
}
}
这篇关于是否可以在 SwiftUI 中向 TextField 添加字距调整?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!