swift - UILabel 继承的 Swift 自定义 UIView
问题描述
我有一个正在尝试解决的继承问题。通常,我在这里只使用多重继承,但 Swift 并没有真正做到这一点。
自定义 UIView
import UIKit
class ValidationView: UIView {
var required:Bool = false
var validRegex:String? = nil
var requiredLbl:UILabel?
private var requiredColor:UIColor = UIColor.red
private var requiredText:String = "*"
private var requiredFont:UIFont = UIFont.systemFont(ofSize: 16.0, weight: UIFont.Weight.bold)
override init(frame: CGRect) {
super.init(frame: frame)
self.setupValidationViews()
}
required init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
self.setupValidationViews()
}
private func setupValidationViews() {
self.requiredLbl = UILabel(frame: CGRect(x: self.frame.width - 30, y: 30, width: 20, height: 20))
self.styleRequiredLabel()
self.addSubview(self.requiredLbl!)
}
func styleRequiredLabel(color:UIColor?, text:String?, font:UIFont?) {
self.requiredColor = color ?? self.requiredColor
self.requiredText = text ?? self.requiredText
self.requiredFont = font ?? self.requiredFont
self.styleRequiredLabel()
}
private func styleRequiredLabel() {
self.requiredLbl?.textColor = self.requiredColor
self.requiredLbl?.text = self.requiredText
self.requiredLbl?.font = self.requiredFont
}
}
自定义 UITextField
import Foundation
import UIKit
@IBDesignable open class CustomTextField: UITextField {
@IBInspectable public var borderWidth: CGFloat = 2.0 {
didSet {
layer.borderWidth = borderWidth
}
}
@IBInspectable public var borderColor: UIColor = UIColor.lightGray {
didSet {
layer.borderColor = borderColor.cgColor
}
}
@IBInspectable public var cornerRadius: CGFloat = 4.0 {
didSet {
layer.cornerRadius = cornerRadius
layer.masksToBounds = true
}
}
}
我希望那个自定义 UITextField 也是一个 ValidationView。我知道我可以做一个协议和扩展,然后让我的 CustomTextField 实现该协议,但这不允许初始化覆盖。我宁愿不必更改实现 ValidationView 的视图的初始化。
可以使用@arturdev 回答来完成这样的事情。我最终得到了这个:
import UIKit
class ValidatableProperties {
var required:Bool
var validRegex:String?
var requiredColor:UIColor
var requiredText:String
var requiredFont:UIFont
init(required:Bool, validRegex:String?, requiredColor:UIColor, requiredText:String, requiredFont:UIFont) {
self.required = required
self.validRegex = validRegex
self.requiredText = requiredText
self.requiredColor = requiredColor
self.requiredFont = requiredFont
}
}
protocol Validatable : UIView {
var validatableProperties:ValidatableProperties! { get set }
var requiredLbl:UILabel! { get set }
func setupValidationDefaults()
func setupValidationViews(frame:CGRect)
func styleRequiredLabel(color:UIColor?, text:String?, font:UIFont?)
}
extension Validatable {
func setupValidationDefaults() {
let props = ValidatableProperties(required: false, validRegex: nil, requiredColor: UIColor.red, requiredText: "*", requiredFont: UIFont.systemFont(ofSize: 16.0, weight: .bold))
self.validatableProperties = props
}
func setupValidationViews(frame:CGRect) {
self.requiredLbl = UILabel(frame: CGRect(x: frame.width, y: 0, width: 20, height: 20))
self.styleRequiredLabel()
self.addSubview(self.requiredLbl)
}
func styleRequiredLabel(color:UIColor?, text:String?, font:UIFont?) {
self.validatableProperties.requiredColor = color ?? self.validatableProperties.requiredColor
self.validatableProperties.requiredText = text ?? self.validatableProperties.requiredText
self.validatableProperties.requiredFont = font ?? self.validatableProperties.requiredFont
self.styleRequiredLabel()
}
private func styleRequiredLabel() {
self.requiredLbl.textColor = self.validatableProperties.requiredColor
self.requiredLbl.text = self.validatableProperties.requiredText
self.requiredLbl.font = self.validatableProperties.requiredFont
}
}
open class ValidationTextField:UITextField, Validatable {
var requiredLbl: UILabel!
var validatableProperties: ValidatableProperties!
override public init(frame: CGRect) {
super.init(frame: frame)
self.setupValidationDefaults()
self.setupValidationViews(frame: frame)
}
public required init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
self.setupValidationDefaults()
self.setupValidationViews(frame: self.frame)
}
}
但这需要将您想要验证的所有类扩展为它们自己的自定义类,每次都需要覆盖 inits 并调用方法。它可以工作,但并不理想,虽然不完全是反模式继承,但肯定有一些代码味道。
解决方案
您应该将ValidationView
其作为协议而不是类,并使您的自定义类符合该协议。
ValidatableView.swift
import UIKit
fileprivate var requiredColor = UIColor.red
fileprivate var requiredText = "*"
fileprivate var requiredFont = UIFont.systemFont(ofSize: 16.0, weight: UIFont.Weight.bold)
fileprivate struct AssociatedKeys {
static var lblKey = "_lblKey_"
}
protocol ValidatableView: class {
var required: Bool {get}
var validRegex: String? {get}
var requiredLbl: UILabel? {get}
}
extension ValidatableView where Self: UIView {
var required: Bool {
return false
}
var validRegex: String? {
return nil
}
var requiredLbl: UILabel? {
get {
return objc_getAssociatedObject(self, &AssociatedKeys.lblKey) as? UILabel
}
set {
objc_setAssociatedObject(self, &AssociatedKeys.lblKey, newValue, .OBJC_ASSOCIATION_RETAIN)
}
}
func setupValidation() {
self.requiredLbl = UILabel(frame: CGRect(x: self.frame.width - 30, y: 30, width: 20, height: 20))
self.requiredLbl?.autoresizingMask = .flexibleWidth
self.styleRequiredLabel()
self.addSubview(self.requiredLbl!)
}
func styleRequiredLabel(color:UIColor? = requiredColor, text:String? = requiredText, font:UIFont? = requiredFont) {
self.requiredLbl?.textColor = requiredColor
self.requiredLbl?.text = requiredText
self.requiredLbl?.font = requiredFont
}
}
CustomTextField.swift
@IBDesignable open class CustomTextField: UITextField {
@IBInspectable public var borderWidth: CGFloat = 2.0 {
didSet {
layer.borderWidth = borderWidth
}
}
@IBInspectable public var borderColor: UIColor = UIColor.lightGray {
didSet {
layer.borderColor = borderColor.cgColor
}
}
@IBInspectable public var cornerRadius: CGFloat = 4.0 {
didSet {
layer.cornerRadius = cornerRadius
layer.masksToBounds = true
}
}
public override init(frame: CGRect) {
super.init(frame: frame)
setupValidation()
}
public required init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
setupValidation()
}
}
extension CustomTextField: ValidatableView { //<- Magic line :)
}
推荐阅读
- javascript - 为什么我的功能组件没有重新渲染?
- .net-core - 在构建时生成 Nuget 包不包括所有依赖项
- java - 我收到错误 java.util.UnknownFormatConversionException: Conversion = '!'
- curl - 在 Informatica 中执行 cURL 脚本
- html - 造型亚马逊附属链接
- javascript - 出现错误无法解构'window.location'的属性'protocol',因为它在构建它时在nextjs应用程序中未定义
- python - 如何在数据框中找到关于另一列值条件的列的最大总和?
- python - 为什么head()方法分组后显示的记录多于默认的5条记录?
- tinymce - 任何想法如何摆脱打印光标,完全卡住
- css - 如何在具有不同内容长度和不同高度的自定义组件中滑动