上面马特发布的答案是正确的。 UITextField 中的清除按钮如果未显示则不存在。可以在UITextField 执行其 layoutSubviews 并检查按钮是否存在后立即尝试访问它。
最简单的方法是继承 UITextField,覆盖 layoutSubviews,如果按钮是第一次显示,则存储它的原始图像以供以后使用,然后在任何后续显示期间应用色调。
下面我将向您展示如何使用扩展来执行此操作,因为这样您就可以将自定义色调应用到任何 UITextField,包括嵌套在 UISearchBar 等现成类中的那些。
玩得开心,喜欢的话就点个赞吧:)
Swift 3.2
这是主要的扩展:
import UIKit
extension UITextField {
private struct UITextField_AssociatedKeys {
static var clearButtonTint = "uitextfield_clearButtonTint"
static var originalImage = "uitextfield_originalImage"
}
private var originalImage: UIImage? {
get {
if let cl = objc_getAssociatedObject(self, &UITextField_AssociatedKeys.originalImage) as? Wrapper<UIImage> {
return cl.underlying
}
return nil
}
set {
objc_setAssociatedObject(self, &UITextField_AssociatedKeys.originalImage, Wrapper<UIImage>(newValue), .OBJC_ASSOCIATION_RETAIN)
}
}
var clearButtonTint: UIColor? {
get {
if let cl = objc_getAssociatedObject(self, &UITextField_AssociatedKeys.clearButtonTint) as? Wrapper<UIColor> {
return cl.underlying
}
return nil
}
set {
UITextField.runOnce
objc_setAssociatedObject(self, &UITextField_AssociatedKeys.clearButtonTint, Wrapper<UIColor>(newValue), .OBJC_ASSOCIATION_RETAIN)
applyClearButtonTint()
}
}
private static let runOnce: Void = {
Swizzle.for(UITextField.self, selector: #selector(UITextField.layoutSubviews), with: #selector(UITextField.uitextfield_layoutSubviews))
}()
private func applyClearButtonTint() {
if let button = UIView.find(of: UIButton.self, in: self), let color = clearButtonTint {
if originalImage == nil {
originalImage = button.image(for: .normal)
}
button.setImage(originalImage?.tinted(with: color), for: .normal)
}
}
func uitextfield_layoutSubviews() {
uitextfield_layoutSubviews()
applyClearButtonTint()
}
}
这里是上面代码中使用的额外sn-ps:
你想以对象方式访问的任何东西的好包装:
class Wrapper<T> {
var underlying: T?
init(_ underlying: T?) {
self.underlying = underlying
}
}
用于查找任何类型的嵌套子视图的少数扩展:
extension UIView {
static func find<T>(of type: T.Type, in view: UIView, includeSubviews: Bool = true) -> T? where T: UIView {
if view.isKind(of: T.self) {
return view as? T
}
for subview in view.subviews {
if subview.isKind(of: T.self) {
return subview as? T
} else if includeSubviews, let control = find(of: type, in: subview) {
return control
}
}
return nil
}
}
UIImage 的扩展以应用淡色
extension UIImage {
func tinted(with color: UIColor) -> UIImage? {
UIGraphicsBeginImageContextWithOptions(self.size, false, self.scale)
color.set()
self.withRenderingMode(.alwaysTemplate).draw(in: CGRect(origin: CGPoint(x: 0, y: 0), size: self.size))
let result = UIGraphicsGetImageFromCurrentImageContext()
UIGraphicsEndImageContext()
return result
}
}
...最后是 Swizzling 的东西:
class Swizzle {
class func `for`(_ className: AnyClass, selector originalSelector: Selector, with newSelector: Selector) {
let method: Method = class_getInstanceMethod(className, originalSelector)
let swizzledMethod: Method = class_getInstanceMethod(className, newSelector)
if (class_addMethod(className, originalSelector, method_getImplementation(swizzledMethod), method_getTypeEncoding(swizzledMethod))) {
class_replaceMethod(className, newSelector, method_getImplementation(method), method_getTypeEncoding(method))
} else {
method_exchangeImplementations(method, swizzledMethod)
}
}
}