首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >是否可以在TextField中添加SwiftUI中的kerning?

是否可以在TextField中添加SwiftUI中的kerning?
EN

Stack Overflow用户
提问于 2019-11-05 15:13:49
回答 1查看 2.3K关注 0票数 4

为了匹配样式指南,我必须向textfield添加kerning,包括占位符和值本身。

使用UIKit,我能够通过以下方法做到这一点:

代码语言:javascript
复制
    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效果,如下所示:

代码语言:javascript
复制
    Text("My label with kerning")
       .kerning(0.7)

不幸的是,我无法找到将kerning样式应用于TextField的值和占位符的方法。对这个有什么想法吗?提前感谢

EN

回答 1

Stack Overflow用户

发布于 2019-11-05 15:39:18

有一个关于HackingwithSwift的简单教程,它展示了如何实现UITextView。它可以很容易地适应UITextField。

下面是一个快速示例,演示如何为您使用UIViewRepresentable UITextField。在文本和占位符上设置kerning。

代码语言:javascript
复制
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,它允许我们访问委托方法。

代码语言:javascript
复制
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了。

代码语言:javascript
复制
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中的占位符设置属性化文本。占位符文本没有被更新,所以我们不需要担心改变它。

下面是我们如何使用它:

代码语言:javascript
复制
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
        }
    }
}
票数 5
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/58714303

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档