无法从 UITextField 中删除 CALayer

Unable to remove a CALayer from UITextField

所以,我有这个自定义 UITextField 并且我有两种方法来添加 CALayer 和删除 CALayer 但是删除不起作用。

@IBDesignable class AppTextField : UITextField {

    private let bottomLine = CALayer()

    override func layoutSubviews() {
        self.font = .systemFont(ofSize: 20)
        self.addBottomLine()
        self.clearButtonMode = .unlessEditing
        super.layoutSubviews()
    }

    func removeBttomLine() {
        bottomLine.removeFromSuperlayer()
    }

    private func addBottomLine() {
        bottomLine.frame = CGRect(origin: CGPoint(x: 0, y: self.frame.height + 4), size: CGSize(width: self.frame.width, height: 1))
        bottomLine.backgroundColor = UIColor.init(hexString: "#DCCFCA")?.cgColor
        self.borderStyle = .none
        self.layer.addSublayer(bottomLine)
    }
}

原因可能是因为 layoutSubviews 方法被多次调用并且层被多次添加。如果您使用故事板或使用 init(frame:) 或自定义 init 方法,请尝试将 addBottomLine 方法移动到 required init?(coder:) 方法,无论哪个只被调用一次。这是一个例子:

@IBDesignable class AppTextField : UITextField {

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

您在 layoutSubviews() 中唯一应该做的就是根据需要更新帧。

当字段 NOT 正在编辑时,这将显示红线,并且当字段 IS 正在编辑:

@IBDesignable class AppTextField : UITextField {

    private let bottomLine = CALayer()

    override init(frame: CGRect) {
        super.init(frame: frame)
        commonInit()
    }
    required init?(coder: NSCoder) {
        super.init(coder: coder)
        commonInit()
    }
    func commonInit() -> Void {
        self.font = .systemFont(ofSize: 20)
        self.backgroundColor = .white
        self.clearButtonMode = .unlessEditing
        self.borderStyle = .none
        bottomLine.backgroundColor = UIColor.red.cgColor
        addBottomLine()
    }

    override func layoutSubviews() {
        super.layoutSubviews()
        var r = bounds
        r.origin.y = bounds.maxY
        r.size.height = 4.0
        bottomLine.frame = r
    }

    func removeBottomLine() {
        bottomLine.removeFromSuperlayer()
    }
    private func addBottomLine() {
        self.layer.addSublayer(bottomLine)
    }

    override func resignFirstResponder() -> Bool {
        super.resignFirstResponder()
        addBottomLine()
        return true
    }
    override func becomeFirstResponder() -> Bool {
        super.becomeFirstResponder()
        removeBottomLine()
        return true
    }
}

您在添加方法中做了 3 件事:

  1. 调整框架
  2. 设置颜色
  3. 添加为子层

并且因为您是从 layoutSubviews 调用它的,所以它被调用了多次,并且您最终添加了多个图层,这就是为什么调用 remove 似乎不起作用的原因。
要使此代码正常工作,您应该将添加部分移至 init(withCoderwithFrame 或两者)。您可以通过设置颜色加入它,因为它可以完成一次。下一部分是调整 layoutSubviews 中的框架,这是必需的,因为图层无法进入自动布局。最后,您将进行创建、添加为子层并设置在初始化时调用一次的部分,并在布局过程中调整多次调用。现在在调用一次时删除 - 这次它会产生可见的效果。