Ios 扩展UITextField以创建可共享组件

Ios 扩展UITextField以创建可共享组件,ios,swift,uikit,Ios,Swift,Uikit,我以编程方式添加了许多UITextField组件,它们似乎都有许多共享行 我想将这些代码提取到某种扩展中,这样我就可以共享代码并减少重复行 但我真的很难做到这一点 我已经在下面添加了这些组件的一些示例,希望您能提供一些关于如何实现这一点的信息,请 let usernameTextField: UITextField = { let tf = UITextField() tf.placeholder = "Username" tf.backgroundColor = UIC

我以编程方式添加了许多UITextField组件,它们似乎都有许多共享行

我想将这些代码提取到某种扩展中,这样我就可以共享代码并减少重复行

但我真的很难做到这一点

我已经在下面添加了这些组件的一些示例,希望您能提供一些关于如何实现这一点的信息,请

let usernameTextField: UITextField = {
    let tf = UITextField()
    tf.placeholder = "Username"
    tf.backgroundColor = UIColor(white: 0, alpha: 0.03)
    tf.font = UIFont.systemFont(ofSize: 14)
    tf.borderStyle = .roundedRect
    tf.autocorrectionType = .no
    tf.autocapitalizationType = .none
    tf.spellCheckingType = .no
    tf.addTarget(self, action: #selector(handleTextInputChange), for: .editingChanged)
    tf.addTarget(nil, action:Selector(("firstResponderAction:")), for:.editingDidEndOnExit)
    return tf
}()

let passwordTextField: UITextField = {
    let tf = UITextField()
    tf.placeholder = "Password"
    tf.backgroundColor = UIColor(white: 0, alpha: 0.03)
    tf.font = UIFont.systemFont(ofSize: 14)
    tf.borderStyle = .roundedRect
    tf.autocorrectionType = .no
    tf.autocapitalizationType = .none
    tf.spellCheckingType = .no
    tf.returnKeyType = .done
    tf.isSecureTextEntry = true
    tf.addTarget(self, action: #selector(handleTextInputChange), for: .editingChanged)
    tf.addTarget(nil, action:Selector(("firstResponderAction:")), for:.editingDidEndOnExit)
    return tf
}()

最简单的解决方案是将
UITextField
子类化,并将共享行包含在重写的
init
方法中。然后,您将创建子类的实例,而不是直接创建
UITextField

例如:

class MyTextField: UITextField {

    override init() {
        super.init()
        self.backgroundColor = UIColor(white: 0, alpha: 0.03)
        self.font = UIFont.systemFont(ofSize: 14)
        self.borderStyle = .roundedRect
        self.autocorrectionType = .no
        self.autocapitalizationType = .none
        tfselfspellCheckingType = .no
    }
}

let passwordTextField = MyTextField()
...
这里没有“可共享组件”问题。唯一难看的是你的代码并不枯燥(“不要重复你自己”)。所以,让它干燥!只需将常见的重复代码分解成一个可以从所有文本字段创建代码调用的函数。例如,假设您正在
viewDidLoad
中执行所有这些操作。然后,您显示的代码可以按如下方式分解:

override func viewDidLoad() {
    super.viewDidLoad()
    func makeTextField() -> UITextField {
        let tf = UITextField()
        tf.backgroundColor = UIColor(white: 0, alpha: 0.03)
        tf.font = UIFont.systemFont(ofSize: 14)
        tf.borderStyle = .roundedRect
        tf.autocorrectionType = .no
        tf.autocapitalizationType = .none
        tf.spellCheckingType = .no
        tf.addTarget(self, action: #selector(handleTextInputChange), for: .editingChanged)
        tf.addTarget(nil, action:Selector(("firstResponderAction:")), for:.editingDidEndOnExit)
        return tf
    }
    let usernameTextField: UITextField = {
        let tf = makeTextField()
        tf.placeholder = "Username"
        return tf
    }()
    let passwordTextField: UITextField = {
        let tf = makeTextField()
        tf.placeholder = "Password"
        tf.returnKeyType = .done
        tf.isSecureTextEntry = true
        return tf
    }()
    // ... do something with text fields here ...
}

这里有另一种方法。使用扩展来设置公共属性,如

extension UITextField{

    func initCommonProperties(withPlaceholder placeholder:String){

        backgroundColor = UIColor(white: 0, alpha: 0.03)
        font = UIFont.systemFont(ofSize: 14)
        borderStyle = .roundedRect
        autocorrectionType = .no
        autocapitalizationType = .none
        spellCheckingType = .no
        addTarget(self, action: #selector(handleTextInputChange), for: .editingChanged)
        addTarget(nil, action:Selector(("firstResponderAction:")), for:.editingDidEndOnExit)
        self.placeholder = placeholder
    }
}

let usernameTextField: UITextField = {
    let tf = UITextField()
    tf.initCommonProperties(withPlaceholder:"Username")
    return tf
}()

let passwordTextField: UITextField = {
    let tf = UITextField()
    tf.initCommonProperties(withPlaceholder:"Password")
    return tf
}()
extension UITextField{

    convenience init(withPlaceholder placeholder:String){

        self.init()

        backgroundColor = UIColor(white: 0, alpha: 0.03)
        font = UIFont.systemFont(ofSize: 14)
        borderStyle = .roundedRect
        autocorrectionType = .no
        autocapitalizationType = .none
        spellCheckingType = .no
        addTarget(self, action: #selector(handleTextInputChange), for: .editingChanged)
        addTarget(nil, action:Selector(("firstResponderAction:")), for:.editingDidEndOnExit)
        self.placeholder = placeholder
    }
}

let usernameTextField = UITextField(withPlaceholder:"Username")
let passwordTextField = UITextField(withPlaceholder:"Password")
您也可以使用函数而不是扩展来执行相同的操作

class MyTextFieldUtils{

    static func initCommonProperties(tf:UITextField){

        tf.backgroundColor = UIColor(white: 0, alpha: 0.03)
        tf.font = UIFont.systemFont(ofSize: 14)
        tf.borderStyle = .roundedRect
        tf.autocorrectionType = .no
        tf.autocapitalizationType = .none
        tf.spellCheckingType = .no
        tf.addTarget(self, action: #selector(handleTextInputChange), for: .editingChanged)
        tf.addTarget(nil, action:Selector(("firstResponderAction:")), for:.editingDidEndOnExit)
    }
}

let usernameTextField: UITextField = {
    let tf = UITextField()
    MyTextFieldUtils.initCommonProperties(tf)
    tf.placeholder = "Username"
    return tf
}()

let passwordTextField: UITextField = {
    let tf = UITextField()
    MyTextFieldUtils.initCommonProperties(tf)
    tf.placeholder = "Password"
    return tf
}()
前者的优点是API简单得多。缺点是现在所有UITextFields都将获得
initCommonProperties
函数

后者的优点是它完全分离了关注点,但代价是更加冗长。但是,您可以通过创建多个函数或多个类来为不同类型的文本框(或任何控件)创建不同的初始值设定项,每个函数或类都具有相同的函数

另一种方法是通过扩展创建方便的初始值设定项,如

extension UITextField{

    func initCommonProperties(withPlaceholder placeholder:String){

        backgroundColor = UIColor(white: 0, alpha: 0.03)
        font = UIFont.systemFont(ofSize: 14)
        borderStyle = .roundedRect
        autocorrectionType = .no
        autocapitalizationType = .none
        spellCheckingType = .no
        addTarget(self, action: #selector(handleTextInputChange), for: .editingChanged)
        addTarget(nil, action:Selector(("firstResponderAction:")), for:.editingDidEndOnExit)
        self.placeholder = placeholder
    }
}

let usernameTextField: UITextField = {
    let tf = UITextField()
    tf.initCommonProperties(withPlaceholder:"Username")
    return tf
}()

let passwordTextField: UITextField = {
    let tf = UITextField()
    tf.initCommonProperties(withPlaceholder:"Password")
    return tf
}()
extension UITextField{

    convenience init(withPlaceholder placeholder:String){

        self.init()

        backgroundColor = UIColor(white: 0, alpha: 0.03)
        font = UIFont.systemFont(ofSize: 14)
        borderStyle = .roundedRect
        autocorrectionType = .no
        autocapitalizationType = .none
        spellCheckingType = .no
        addTarget(self, action: #selector(handleTextInputChange), for: .editingChanged)
        addTarget(nil, action:Selector(("firstResponderAction:")), for:.editingDidEndOnExit)
        self.placeholder = placeholder
    }
}

let usernameTextField = UITextField(withPlaceholder:"Username")
let passwordTextField = UITextField(withPlaceholder:"Password")

希望这有帮助

请注意,如果这些是实例属性,那么您的代码是非法的。在初始化
self
的实例属性时,不能谈论
self
(就像在
addTarget
调用中一样)。只是一个友好的注释。当你提到像“干燥”这样的东西时,你应该把第一个引用作为一个链接,这样其他人就可以深入了解它的含义。同意@LeoDabus。这看起来是剪切复制粘贴错误,因为您在直接设置属性时引用的是“tf”。@LeoDabus Good spot,是的,我在这里复制粘贴了OPs代码,将进行更改并记下以备将来检查。