IOS 13 Установите цвет заполнителя UISearchTextField

Как установить цвет заполнителя для iOS 13 UISearchTextField?

Я попробовал следующее безуспешно:

searchField.attributedPlaceholder = NSAttributedString(string: "Some placeholder", attributes: [NSAttributedString.Key.foregroundColor: UIColor.red])

Это ошибка в текущей бета-версии или я что-то пропустил? Я использую Xcode 11, бета 7.

Ответ 1

Вы можете попробовать это с Xcode 11, iOS 13

extension UISearchBar {

    func getTextField() -> UITextField? { return value(forKey: "searchField") as? UITextField }
    func set(textColor: UIColor) { if let textField = getTextField() { textField.textColor = textColor } }
    func setPlaceholder(textColor: UIColor) { getTextField()?.setPlaceholder(textColor: textColor) }
    func setClearButton(color: UIColor) { getTextField()?.setClearButton(color: color) }

    func setTextField(color: UIColor) {
        guard let textField = getTextField() else { return }
        switch searchBarStyle {
        case .minimal:
            textField.layer.backgroundColor = color.cgColor
            textField.layer.cornerRadius = 8
        case .prominent, .default: textField.backgroundColor = color
        @unknown default: break
        }
    }

    func setSearchImage(color: UIColor) {
        guard let imageView = getTextField()?.leftView as? UIImageView else { return }
        imageView.tintColor = color
        imageView.image = imageView.image?.withRenderingMode(.alwaysTemplate)
    }
}

private extension UITextField {

private class Label: UILabel {
    private var _textColor = UIColor.lightGray
    override var textColor: UIColor! {
        set { super.textColor = _textColor }
        get { return _textColor }
    }

    init(label: UILabel, textColor: UIColor = .lightGray) {
        _textColor = textColor
        super.init(frame: label.frame)
        self.text = label.text
        self.font = label.font
    }

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


private class ClearButtonImage {
    static private var _image: UIImage?
    static private var semaphore = DispatchSemaphore(value: 1)
    static func getImage(closure: @escaping (UIImage?)->()) {
        DispatchQueue.global(qos: .userInteractive).async {
            semaphore.wait()
            DispatchQueue.main.async {
                if let image = _image { closure(image); semaphore.signal(); return }
                guard let window = UIApplication.shared.windows.first else { semaphore.signal(); return }
                let searchBar = UISearchBar(frame: CGRect(x: 0, y: -200, width: UIScreen.main.bounds.width, height: 44))
                window.rootViewController?.view.addSubview(searchBar)
                searchBar.text = ""
                searchBar.layoutIfNeeded()
                _image = searchBar.getTextField()?.getClearButton()?.image(for: .normal)
                closure(_image)
                searchBar.removeFromSuperview()
                semaphore.signal()
            }
        }
    }
}

func setClearButton(color: UIColor) {
    ClearButtonImage.getImage { [weak self] image in
        guard   let image = image,
            let button = self?.getClearButton() else { return }
        button.imageView?.tintColor = color
        button.setImage(image.withRenderingMode(.alwaysTemplate), for: .normal)
    }
}

var placeholderLabel: UILabel? { return value(forKey: "placeholderLabel") as? UILabel }

func setPlaceholder(textColor: UIColor) {
    guard let placeholderLabel = placeholderLabel else { return }
    let label = Label(label: placeholderLabel, textColor: textColor)
    placeholderLabel.removeFromSuperview() // To remove existing label. Otherwise it will overwrite it if called multiple times.
    setValue(label, forKey: "placeholderLabel")
}

func getClearButton() -> UIButton? { return value(forKey: "clearButton") as? UIButton }

}

Использование:

    searchBarObj.placeholder = "placeholder text"
    searchBarObj.set(textColor: .blue)
    searchBarObj.setTextField(color: UIColor.gray)
    searchBarObj.setPlaceholder(textColor: .red)
    searchBarObj.setSearchImage(color: .black)
    searchBarObj.setClearButton(color: .red)

Ответ 2

        let searchTextField: UITextField? = searchBar.value(forKey: "searchField") as? UITextField

        if searchTextField!.responds(to: #selector(getter: UITextField.attributedPlaceholder))
    {
        let attributeDict = [NSAttributedString.Key.foregroundColor: UIColor.red]
        searchTextField!.attributedPlaceholder = NSAttributedString(string: "RED PLACEHOLDER TEXT", attributes: attributeDict)
    }