为了匹配样式指南,我必须向textfield添加kerning,包括占位符和值本身。
使用UIKit,我能够通过以下方法做到这一点:
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元素应用kerning效果,如下所示:
Text("My label with kerning")
.kerning(0.7)不幸的是,我无法找到将kerning样式应用于TextField的值和占位符的方法。对这个有什么想法吗?提前感谢
发布于 2019-11-05 15:39:18
有一个关于HackingwithSwift的简单教程,它展示了如何实现UITextView。它可以很容易地适应UITextField。
下面是一个快速示例,演示如何为您使用UIViewRepresentable UITextField。在文本和占位符上设置kerning。
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上设置kerning。借鉴克斯坦蒂诺·皮斯塔那在他的中篇中所做的出色工作,我们需要做更多的工作。
首先,我们需要创建一个包装版的UITextField,它允许我们访问委托方法。
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,它就会像预期的那样工作。
现在我们可以在WrappedTextField中使用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中的占位符设置属性化文本。占位符文本没有被更新,所以我们不需要担心改变它。
下面是我们如何使用它:
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
}
}
}https://stackoverflow.com/questions/58714303
复制相似问题