【问题标题】:Swift - code re-useSwift - 代码重用
【发布时间】:2017-07-28 06:51:23
【问题描述】:

我正在寻求一些关于代码重用的建议。

我有一个视图控制器(在这个阶段)有 12 个标签和 12 个文本字段。

对于每个标签和字段,都有重复的代码行(请参阅下面的注释行)。

我想知道在创建标签和文本字段时重复使用代码行的最佳方法,而不是一直重写它们。

我已经研究过扩展,创建了一个类,还继承了常见的代码行,但我一直碰壁。

我已经使用了一个类来填充文本字段并了解它是如何工作的,但我似乎无法将其他常见属性添加到该类中。谢谢

示例:

let LabelA = UILabel()
// LabelA.backgroundColor = .clear
// LabelA.widthAnchor.constraint(equalToConstant: 150).isActive = true
// LabelA.font = LabelA.font.withSize(18)
// LabelA.textAlignment = .left
LabelA.text = “This is my 1st label of 12“

let LabelB = UILabel()
// LabelB.backgroundColor = .clear
// LabelB.widthAnchor.constraint(equalToConstant: 150).isActive = true
// LabelB.font = LabelB.font.withSize(18)
// LabelB.textAlignment = .left
LabelB.text = “This is my 2nd label of 12“

let LabelC = UILabel()
// LabelC.backgroundColor = .clear
// LabelC.widthAnchor.constraint(equalToConstant: 150).isActive = true
// LabelC.font = LabelC.font.withSize(18)
// LabelC.textAlignment = .left
LabelC.text = “This is my 3rd label of 12“

** 更新 **

感谢所有的cmets。

我现在通过向我的填充类添加一个 func 来重用常见的代码行。

很遗憾,文本字段填充不再起作用。

class PaddedTextField: UITextField {

    let padding = UIEdgeInsets(top: 0, left: 5, bottom: 0, right: 5);

    override func textRect(forBounds bounds: CGRect) -> CGRect {
        return UIEdgeInsetsInsetRect(bounds, padding)
    }

    override func placeholderRect(forBounds bounds: CGRect) -> CGRect {
        return UIEdgeInsetsInsetRect(bounds, padding)
    }

    override func editingRect(forBounds bounds: CGRect) -> CGRect {
        return UIEdgeInsetsInsetRect(bounds, padding)
    }

    func createText(with text: String) -> UITextField {
        let txtField = UITextField()
        txtField.backgroundColor = .clear
        txtField.widthAnchor.constraint(equalToConstant: 250).isActive = true
        txtField.layer.borderWidth = 1
        txtField.layer.borderColor = UIColor(r: 203, g: 203, b: 203).cgColor
        txtField.layer.cornerRadius = 5
        txtField.layer.masksToBounds = true
        txtField.placeholder = text
        txtField.isEnabled = true
        return txtField
    }
} 

所以,这行代码在没有添加字段填充的情况下工作......

let textFieldA = PaddedTextField().createText(with: "placeholder text...")

...这适用于字段填充,但不能重复使用常见的代码行。

let textFieldB = PaddedTextField()
textFieldB.backgroundColor = .clear
textFieldB.widthAnchor.constraint(equalToConstant: 250).isActive = true
textFieldB.layer.borderWidth = 1
textFieldB.layer.borderColor = UIColor(r: 203, g: 203, b: 203).cgColor
textFieldB.layer.cornerRadius = 5
textFieldB.layer.masksToBounds = true
textFieldB.placeholder = "textFieldB placeholder text..."
textFieldB.isEnabled = true

我不确定我有哪些错误/不明白的部分。谢谢。

【问题讨论】:

  • “子类化常见的代码行,但我一直在碰壁”。墙壁是什么?
  • @Lawliet 我一直在打的墙是添加 func 之类的东西,但没有得到我期望的结果。根据我对 OP 的更新。

标签: swift uitextfield uilabel


【解决方案1】:

创建具有这些重复属性的 UILabel 子类可能是最有效和最干净的方法。

第二种方法是创建一个工厂

例如:

private class func factoryLabel() -> UILabel
{
   let label = UILabel()
   label.backgroundColor = .clear
   label.widthAnchor.constraint(equalToConstant: 150).isActive = true
   label.font = LabelC.font.withSize(18)
   label.textAlignment = .left

   return label
}

...

let LabelB = myClass.factoryLabel()
LabelB.text = “This is my 2nd label of 12“

这里的例子是一个类func,你需要调用它作为一个静态的func,即带有类的名字。


更新

在您的更新中,您并没有完全使用工厂,而是创建了 UITextField 的子类,并在该子类中分解了 UITextField(即 分解了您的子类)

由于您已经有了具有工厂的子类,因此实际上不需要将您的类更改为:

class PaddedTextField:UITextField
{
    private let padding:UIEdgeInsets = UIEdgeInsets(top: 0, left: 5, bottom: 0, right: 5);

    init(with text:String)
    {
        super.init(frame:CGRect.zero)
        backgroundColor = .clear
        widthAnchor.constraint(equalToConstant:250).isActive = true
        layer.borderWidth = 1
        layer.borderColor = UIColor(r: 203, g: 203, b: 203).cgColor
        layer.cornerRadius = 5
        layer.masksToBounds = true
        placeholder = text
        isEnabled = true
    }

    required init?(coder aDecoder:NSCoder)
    {
        return nil
    }

    override func textRect(forBounds bounds:CGRect) -> CGRect
    {
        return UIEdgeInsetsInsetRect(bounds, padding)
    }

    override func placeholderRect(forBounds bounds:CGRect) -> CGRect
    {
        return UIEdgeInsetsInsetRect(bounds, padding)
    }

    override func editingRect(forBounds bounds:CGRect) -> CGRect
    {
        return UIEdgeInsetsInsetRect(bounds, padding)
    }
}

现在像这样实例化它:

let textFieldA = PaddedTextField(with: "placeholder text...")

【讨论】:

  • 谢谢,我已经实现了你的部分答案,我会更多地研究“工厂的”。
  • @K1llarney 刚刚更新了我的答案,请看一下。
  • 谢谢零,你是冠军。
【解决方案2】:

简单的解决方案是将文本字符串作为参数传递并返回标签的函数:

func createLabel(with text: String) -> UILabel
{
   let label = UILabel()
   label.backgroundColor = .clear
   label.widthAnchor.constraint(equalToConstant: 150).isActive = true
   label.font = LabelC.font.withSize(18)
   label.textAlignment = .left
   label.text = text
   return label
}

let labelA = createLabel(with: "This is my 1st label of 12")
let labelB = createLabel(with: "This is my 2nd label of 12")
let labelC = createLabel(with: "This is my 3rd label of 12")

** 更新 **

在子类化UITextField 的情况下,我建议覆盖两个指定的init 方法,并添加一个用于附加设置的通用方法和一个用于设置文本属性的类方法。好处是,如果在 Interface Builder 中使用 init(coder 创建文本字段,也会考虑额外的设置

class PaddedTextField: UITextField {

    class func create(with text: String) -> PaddedTextField
    {
        let field = PaddedTextField()
        field.text = text
        return field
    }

    let padding = UIEdgeInsets(top: 0, left: 5, bottom: 0, right: 5);

    override func textRect(forBounds bounds: CGRect) -> CGRect {
        return UIEdgeInsetsInsetRect(bounds, padding)
    }

    override func placeholderRect(forBounds bounds: CGRect) -> CGRect {
        return UIEdgeInsetsInsetRect(bounds, padding)
    }

    override func editingRect(forBounds bounds: CGRect) -> CGRect {
        return UIEdgeInsetsInsetRect(bounds, padding)
    }

    override init(frame: CGRect) {
        super.init(frame: frame)
        setup()
    }

    required init?(coder aDecoder: NSCoder) {
        super.init(coder: aDecoder)
        setup()
    }

    func setup() {
        self.backgroundColor = .clear
        self.widthAnchor.constraint(equalToConstant: 250).isActive = true
        self.layer.borderWidth = 1
        self.layer.borderColor = UIColor(white: 0.796, alpha: 1.0).cgColor
        self.layer.cornerRadius = 5
        self.layer.masksToBounds = true
        self.placeholder = text
        self.isEnabled = true
    }
}


let labelA = PaddedTextField.create(with: "This is my 1st label of 12")
let labelB = PaddedTextField.create(with: "This is my 2nd label of 12")
let labelC = PaddedTextField.create(with: "This is my 3rd label of 12")

【讨论】:

  • 谢谢,我已经实现了你的回答,但仍然存在我的 OP 更新中提到的问题。
【解决方案3】:

在这种情况下,我会使用 stackview(这里有一个很棒的 talk),所以你不必一直被填充等困扰。

你可以像这样创建一个函数:

func mkInput(with text: String) -> (UILabel, UITextField) {
    let label: UILabel
    let textField: UITextField
    // config these as you want...
    return (label, textField)
}

您可以从以下字符串创建集合:

let inputs: [(UILabel, UITextField)] = labelStrings.map { mkInput(with: $0) }

等等。 :)

【讨论】:

  • 感谢您的意见亚当。仅供参考...我在设置标签之后以及设置文本字段之后使用堆栈视图。我正在使用填充,因为这些字段是以编程方式创建的,带有边框,并且它们需要在前面的填充。
猜你喜欢
  • 1970-01-01
  • 2018-04-22
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-06-12
  • 2015-08-23
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多