Come modificare la tonalità di colore del pulsante cancella in un UITextField

Ho un auto-generata pulsante “clear” sul mio UITextfield, di default con il blu, tonalità di colore. Non riesco a cambiare il colore della tinta di bianco. Ho provato a modificare lo storyboard e il codice senza successo, e io non voglio utilizzare un’immagine personalizzata.

Come posso cambiare l’impostazione predefinita, il pulsante ” clear colore della tinta senza l’utilizzo di un immagine personalizzata?

Come modificare la tonalità di colore del pulsante cancella in un UITextField

  • Sembra global tinta non è onorato per il UITextField pulsante cancella (per qualsiasi motivo!), è possibile controllare questa risposta e questa risposta per vedere come sono gli altri a farlo. Sembra che devi creare il proprio pulsante.
  • Ok, vi do! Grazie per il vostro aiuto 😉
InformationsquelleAutor Niels Robben | 2015-01-14



21 Replies
  1. 70

    Qui si va!

    Un TintTextField.

    Non utilizza nessuna immagine personalizzata o aggiunta di pulsanti etc.

    Come modificare la tonalità di colore del pulsante cancella in un UITextField

    class TintTextField: UITextField {
    
         var tintedClearImage: UIImage?
    
         required init(coder aDecoder: NSCoder) {
           super.init(coder: aDecoder)
           self.setupTintColor()
         }
    
         override init(frame: CGRect) {
           super.init(frame: frame)
           self.setupTintColor()
         }
    
         func setupTintColor() {
           self.borderStyle = UITextField.BorderStyle.roundedRect
           self.layer.cornerRadius = 8.0
           self.layer.masksToBounds = true
           self.layer.borderColor = self.tintColor.cgColor
           self.layer.borderWidth = 1.5
           self.backgroundColor = .clear
           self.textColor = self.tintColor
         }
    
        override func layoutSubviews() {
            super.layoutSubviews()
            self.tintClearImage()
        }
    
        private func tintClearImage() {
            for view in subviews {
                if view is UIButton {
                    let button = view as! UIButton
                    if let image = button.image(for: .highlighted) {
                        if self.tintedClearImage == nil {
                            tintedClearImage = self.tintImage(image: image, color: self.tintColor)
                        }
                        button.setImage(self.tintedClearImage, for: .normal)
                        button.setImage(self.tintedClearImage, for: .highlighted)
                    }
                }
            }
        }
    
        private func tintImage(image: UIImage, color: UIColor) -> UIImage {
            let size = image.size
    
            UIGraphicsBeginImageContextWithOptions(size, false, image.scale)
            let context = UIGraphicsGetCurrentContext()
            image.draw(at: .zero, blendMode: CGBlendMode.normal, alpha: 1.0)
    
            context?.setFillColor(color.cgColor)
            context?.setBlendMode(CGBlendMode.sourceIn)
            context?.setAlpha(1.0)
    
            let rect = CGRect(x: CGPoint.zero.x, y: CGPoint.zero.y, width: image.size.width, height: image.size.height)
            UIGraphicsGetCurrentContext()?.fill(rect)
            let tintedImage = UIGraphicsGetImageFromCurrentImageContext()
            UIGraphicsEndImageContext()
    
            return tintedImage ?? UIImage()
        }
     }
    • Sembra molto promettente. Si può fornire un Obiettivo-C versione?
    • Sono in grado di leggere Objective-C, se sono di buon umore, ma fidati di me non mi vuole vedere scrivere in Objective-C. Sorta di nuovo iOS, e si è unito il treno con la Swift. 🙂
    • Non nome del campo di testo personalizzato classe di partenza con UI. Che prefisso è riservata per Apple.
    • Questo è molto intelligente, e penso che si dovrebbe ottenere il bounty – mi piace l’uso di layoutSubviews per risolvere il problema di quando per accedere al pulsante “clear” – ma ha un leggero inefficienza: si imposta la chiara immagine del pulsante ogni volta che l’utente modifica (ad esempio, dopo ogni carattere viene inserito nel campo di testo).
    • È possibile memorizzare nella cache le colorate immagini, così come non ricalcolare ogni volta.
    • Aggiunto un semplice meccanismo di cache. E ‘ anche limitato nel sens che non si otterrebbe la componente aggiornato se si modifica la tinta in una fase successiva… Ma credo che sia ok questa fase. 🙂
    • Questo è un molto bello e intelligente soluzione! Mi piace questo. Vi ringrazio molto!
    • Grazie, MOLTO utile! Se qualcuno volesse utilizzare Mikael chiaro, ma senza il bordo intorno alla TintTextField, è sufficiente rimuovere le seguenti righe da setupTintColor()…. 1. borderStyle = UITextBorderStyle.RoundedRect 2. livello.cornerRadius = 8.0 3. livello.masksToBounds = true 4. livello.borderColor = tinta.CGColor 5. livello.borderWidth = 1.5
    • Basato su @MikaelHellman codice ho creato un Obiettivo di categoria C per UITextField che permette sottoclassi di condividere facilmente il campo di testo tintColor con il pulsante clear image -> gist.github.com/somethingkindawierd/a9f2cd3349685ab09757
    • Solo curioso di sapere perché è hardcoded una scala di 2 UIGraphicsBeginImageContextWithOptions. Forse è meglio usare image.scale invece?
    • Buona pesca. Ho copia incollato il codice da un altro laboratorio di progetto in cui ho voluto che la bilancia sia hardcoded. Ho aggiornato il codice qui.
    • Poiché la domanda per una strada che non uso cusom immagini (che è preferibile, a mio parere). Non so se c’è un modo meno “sporca” soluzione per ottenere questo?
    • Non funziona più in iOS 11. Pulsante alfa è di sbagliato con questa soluzione
    • Non guardare bene su iOS 11. Mi consiglia di controllare la mia risposta qui sotto e invece di usare la mia libreria LSCategories per impostare questo con una sola riga di codice 🙂

  2. 22

    Il motivo per cui stai avendo problemi a fare questo è che il pulsante cancella le immagini non sono colorate. Sono solo le immagini normali.

    Il pulsante clear è un pulsante, all’interno dell’UITextField. Come qualsiasi tasto, si può avere un’immagine e non. In particolare, si è due immagini: una per lo stato Normale, e uno per il Evidenziati. Il blu per cui l’OP è la possibilità di contestare è l’immagine Evidenziata, e può essere catturato da l’esecuzione di questo codice al momento in cui il pulsante “clear” è presente:

        let tf = self.tf //the text view
        for sv in tf.subviews as! [UIView] {
            if sv is UIButton {
                let b = sv as! UIButton
                if let im = b.imageForState(.Highlighted) {
                    //im is the blue x
                }
            }
        }

    Una volta che si cattura, si noterà che si tratta di un 14×14 doppia risoluzione di immagine tiff, e qui è:

    Come modificare la tonalità di colore del pulsante cancella in un UITextField

    In teoria, è possibile modificare l’immagine di un colore diverso, e si può assegnare come il testo del pulsante cancella l’immagine in evidenza di stato. Ma in pratica questo non è affatto facile da fare, perché il pulsante non è sempre presente; non è possibile fare riferimento ad esso quando è assente (non e ‘ solo la invisibile; è una realtà non fanno parte della gerarchia della vista, quindi non c’è alcun modo per accedere).

    Esiste, inoltre, un UITextField API per personalizzare il pulsante clear.

    Così, la soluzione più semplice è quello che si consiglia qui: creare un pulsante personalizzato Normale e immagini Evidenziate e di fornire il UITextField del rightView. Si imposta quindi la clearButtonMode Mai (dal momento che si utilizza la vista destra, invece) e il rightViewMode a ciò che si desidera.

    Come modificare la tonalità di colore del pulsante cancella in un UITextField

    Del corso, quindi, di rilevare un tap su questo pulsante e rispondere cancellando il testo del campo di testo, ma questo è facile da fare, e viene lasciato come esercizio per il lettore.

    • Non credo che si potesse cambiare l’immagine evidenziata la renderingMode per UIImageRenderingModeAlwaysTemplate? 🙂
    • Alcun effetto. Provare. Come ho detto all’inizio, queste immagini non vengono falsati.
    • annuisce. ho fatto vedere che, ma non sapevo se fosse dipendente come il controllo reso il pulsante cancella. Grazie del chiarimento! Si potrebbe pensare che sarebbe un fix minori per Apple, ma l’originale radar #14970472 dal 2013 è ancora aperta.
    • Il sottolineato stato dell’immagine sembra rispondere a UITextField.appearance().tintColor. Quella normale è sempre in grigio chiaro.
    • Matt, non è forse una versione trasparente del pulsante cancella? In modo che ho aggiunto al mio progetto e cambiarlo con un colore diverso.
  3. 15

    Basandosi su @Mikael Hellman risposta ho preparato simili attuazione di UITextField sottoclasse per Objective-c, con La differenza che mi permette di avere colori distinti per il Normale e ha Evidenziato uniti.

    .h file

    #import <UIKit/UIKit.h>
    
    
    @interface TextFieldTint : UITextField
    
    -(void) setColorButtonClearHighlighted:(UIColor *)colorButtonClearHighlighted;
    -(void) setColorButtonClearNormal:(UIColor *)colorButtonClearNormal;
    
    @end

    .m file

    #import "TextFieldTint.h"
    
    @interface TextFieldTint()
    
    @property (nonatomic,strong) UIColor *colorButtonClearHighlighted;
    @property (nonatomic,strong) UIColor *colorButtonClearNormal;
    
    @property (nonatomic,strong) UIImage *imageButtonClearHighlighted;
    @property (nonatomic,strong) UIImage *imageButtonClearNormal;
    
    
    @end
    
    @implementation TextFieldTint
    
    
    -(void) layoutSubviews
    {
        [super layoutSubviews];
        [self tintButtonClear];
    }
    
    -(void) setColorButtonClearHighlighted:(UIColor *)colorButtonClearHighlighted
    {
        _colorButtonClearHighlighted = colorButtonClearHighlighted;
    }
    
    -(void) setColorButtonClearNormal:(UIColor *)colorButtonClearNormal
    {
        _colorButtonClearNormal = colorButtonClearNormal;
    }
    
    -(UIButton *) buttonClear
    {
        for(UIView *v in self.subviews)
        {
            if([v isKindOfClass:[UIButton class]])
            {
                UIButton *buttonClear = (UIButton *) v;
                return buttonClear;
            }
        }
        return nil;
    }
    
    
    
    -(void) tintButtonClear
    {
        UIButton *buttonClear = [self buttonClear];
    
        if(self.colorButtonClearNormal && self.colorButtonClearHighlighted && buttonClear)
        {
            if(!self.imageButtonClearHighlighted)
            {
                UIImage *imageHighlighted = [buttonClear imageForState:UIControlStateHighlighted];
                self.imageButtonClearHighlighted = [[self class] imageWithImage:imageHighlighted
                                                                      tintColor:self.colorButtonClearHighlighted];
            }
            if(!self.imageButtonClearNormal)
            {
                UIImage *imageNormal = [buttonClear imageForState:UIControlStateNormal];
                self.imageButtonClearNormal = [[self class] imageWithImage:imageNormal
                                                                 tintColor:self.colorButtonClearNormal];
            }
    
            if(self.imageButtonClearHighlighted && self.imageButtonClearNormal)
            {
                [buttonClear setImage:self.imageButtonClearHighlighted forState:UIControlStateHighlighted];
                [buttonClear setImage:self.imageButtonClearNormal forState:UIControlStateNormal];
            }
        }
    }
    
    
    + (UIImage *) imageWithImage:(UIImage *)image tintColor:(UIColor *)tintColor
    {
        UIGraphicsBeginImageContextWithOptions(image.size, NO, 0.0);
        CGContextRef context = UIGraphicsGetCurrentContext();
    
        CGRect rect = (CGRect){ CGPointZero, image.size };
        CGContextSetBlendMode(context, kCGBlendModeNormal);
        [image drawInRect:rect];
    
        CGContextSetBlendMode(context, kCGBlendModeSourceIn);
        [tintColor setFill];
        CGContextFillRect(context, rect);
    
        UIImage *imageTinted  = UIGraphicsGetImageFromCurrentImageContext();
        UIGraphicsEndImageContext();
        return imageTinted;
    }
    @end
    • Non sembra di lavorare in iOS 9+
    • Sto ancora usando questo in produzione build – funziona senza problemi su iOS 10+
  4. 12

    In Swift è possibile scrivere l’estensione e utilizzare su qualsiasi campo di testo del tuo progetto.

    extension UITextField {
        func modifyClearButton(with image : UIImage) {
            let clearButton = UIButton(type: .custom)
            clearButton.setImage(image, for: .normal)
            clearButton.frame = CGRect(x: 0, y: 0, width: 15, height: 15)
            clearButton.contentMode = .scaleAspectFit
            clearButton.addTarget(self, action: #selector(UITextField.clear(_:)), for: .touchUpInside)
            rightView = clearButton
            rightViewMode = .whileEditing
        }
    
        func clear(_ sender : AnyObject) {
            self.text = ""
            sendActions(for: .editingChanged)
        }
    }
    • Questo funziona alla grande, ma è una migliore corrispondenza con il pulsante originale se il telaio larghezza è pari a 27, con la dotazione di immagine come 15×15 (@1x) e il contenuto è impostato sulla modalità UIViewContentModeCenter.
  5. 11

    Per Swift 4, aggiungere a questo una sottoclasse di UITextField:

    import UIKit
    
    class CustomTextField: UITextField {
    
        override func layoutSubviews() {
            super.layoutSubviews()
    
            for view in subviews {
                if let button = view as? UIButton {
                    button.setImage(button.image(for: .normal)?.withRenderingMode(.alwaysTemplate), for: .normal)
                    button.tintColor = .white
                }
            }
        }
    }
    • È tintColor non ereditaria?
    • Non funziona per me in iOS 12. Il pulsante clear non cambi colore.
    • sì, lo è, ma il pulsante “clear” non è, così non è possibile accedere direttamente ad essa, è necessario attraversare la sottoview albero.
  6. 5

    È possibile utilizzare KVO per accedere al pulsante cancella e aggiornamento:

        UIButton *clearButton = [myTextField valueForKey:@"_clearButton"]
        if([clearButton respondsToSelector:@selector(setImage:forState:)]){
    
            //ensure that the app won't crash in the future if _clearButton reference changes to a different class instance
            [clearButton setImage:[UIImage imageNamed:@"MyImage.png"] forState:UIControlStateNormal];
    
        }

    Nota: Questa soluzione non è a prova di futuro – se Apple cambia l’attuazione del pulsante elimina questo sarà normalmente smettere di lavorare.

    • Assolutamente terribile idea. Abbiamo usato per fare qualcosa di simile su UIAlertViews l’accesso ai pulsanti. Quando apple ha cambiato la loro attuazione, tutti gli acquisti in-app ha smesso di funzionare e ci siamo lasciati con settimane di “riparazione”. This solution may not be future proof non è abbastanza di un avvertimento 😉
    • Webster, ha capito che l’attuazione di UITextField possono cambiare, ma siamo personalizzazione di un pulsante clear – non esattamente funzionalità critiche. La cosa peggiore che accadrà è che il pulsante clear non ottenere personalizzato.
    • che non è vero. L’applicazione potrebbe bloccarsi. Se si dispone di questa casella di testo di un form di login, gli utenti improvvisamente non si può usare la tua applicazione più
    • Webster, come è questo andare in crash? valueForKey ritorna nil se il pulsante non esiste ed è sicuro al messaggio di nil. Apple avrebbe dovuto sostituire _clearButton con una classe diversa. Io aggiornare la mia risposta di utilizzare respondsToSelector per renderlo sicuro al 100%
    • Funziona, ma direi che è molto rischioso. valueForKey può mandare in crash se valueForUndefinedKey non è implementata. È possibile verificare che, per esempio, si blocca se si tenta di utilizzarlo su non esistente tasto UIViewController oggetto (NSUnknownKeyException). Sembra che per UIButton attualmente non crash per non esistente chiavi, in modo che probabilmente UIButton implementa valueForUndefinedKey, tuttavia mi sento di non dare per scontato che sarà sempre implementare in futuro e, nel caso di Apple, la cambia, allora potrebbe bloccarsi.
  7. 3

    Potrebbe essere anche più facile che il più alto rating risposta, disponibile per iOS 7 e versioni successive.

    @interface MyTextField
    
    @end
    
    @implementation MyTextField
    
    - (void)layoutSubviews {
        [super layoutSubviews];
    
        for (UIView *subView in self.subviews) {
            if ([subView isKindOfClass:[UIButton class]]) {
                UIButton *button = (UIButton *)subView;
                [button setImage:[[button imageForState:UIControlStateNormal] imageWithRenderingMode:UIImageRenderingModeAlwaysTemplate]
                        forState:UIControlStateNormal];
                button.tintColor = self.tintColor;
            }
        }
    }
    
    @end
    • È tintColor non ereditaria?
  8. 3

    Ecco Swift 3 aggiornato soluzione:

    extension UITextField {
        func modifyClearButtonWithImage(image : UIImage) {
            let clearButton = UIButton(type: .custom)
            clearButton.setImage(image, for: .normal)
            clearButton.frame = CGRect(x: 0, y: 0, width: 15, height: 15)
            clearButton.contentMode = .scaleAspectFit
            clearButton.addTarget(self, action: #selector(self.clear(sender:)), for: .touchUpInside)
            self.rightView = clearButton
            self.rightViewMode = .whileEditing
        }
    
        func clear(sender : AnyObject) {
            self.text = ""
        }
    }

    Godere 😉

  9. 3

    Se si utilizza UIAppearance nell’app è possibile impostare la tinta per il pulsante cancella in fase di runtime.

    let textField = UITextField.appearance()
    textField.tintColor = .green

    All’avvio noi chiamiamo una funzione di classe nel nostro AppDelegate che ha un certo numero di altri controlli, che hanno la loro .appearance() configurato in esso.

    Supponiamo che la vostra classe per impostare l’aspetto dell’applicazione si chiama Beautyify si potrebbe creare qualcosa di simile a questo:

    @objc class Beautify: NSObject {
        class func applyAppearance() {
            let tableViewAppearance = UITableView.appearance()
            tableViewAppearance.tintColor = .blue
    
            let textField = UITextField.appearance()
            textField.tintColor = .green
        }
    }

    Quindi, all’interno di AppDelegate didFinishLaunchingWithOptions basta chiamare.

    Beautify.applyAppearance()

    È un ottimo modo per configurare l’aspetto delle cose nella vostra applicazione, tutti allo stesso tempo.

    • Questo sembra funzionare per il cursore, ma non per il tasto clear (x).
    • Oops, il mio male. Che non di lavoro per la sottolineato stato del pulsante cancella. Lo stato normale soggiorni di colore grigio chiaro…
  10. 2

    Questo ha funzionato per me con objective-C. ho tirato pezzi da altri thread su questo argomento e si avvicinò con questa soluzione:

    UIButton *btnClear = [self.textFieldUserID valueForKey:@"clearButton"];
    [btnClear setImage:[UIImage imageNamed:@"facebookLoginButton"] forState:UIControlStateNormal];
  11. 2

    È possibile utilizzare la vostra icona personalizzata e funziona in iOS 11,

    searchBar.setImage(UIImage(named: "ic_clear"), for: .clear, state: .normal)
  12. 1

    Dopo aver attraversato tutte le risposte e le possibilità, ho trovato questo semplice e dritto in avanti la soluzione.

    -(void)updateClearButtonColor:(UIColor *)color ofTextField:(UITextField *)textField {
    
        UIButton *btnClear = [textField valueForKey:@"_clearButton"];
        UIImage * img = [btnClear imageForState:UIControlStateNormal];
    
        if (img) {
            UIImage * renderingModeImage = [img imageWithRenderingMode:UIImageRenderingModeAlwaysTemplate];
            [btnClear setImage:renderingModeImage forState:UIControlStateNormal];
            //-- Add states you want to update
            [btnClear setImage:renderingModeImage forState:UIControlStateSelected];
        }
    
        [btnClear setTintColor:color];
    }
    
    
    [self updateClearButtonColor:[UIColor whiteColor] ofTextField:self.textField];
    • Facendo valueForKey:@"_clearButton" utilizza un privato API che possono rompere in una futura versione iOS e potrebbe ottenere la vostra applicazione rifiutata da Apple.
  13. 1

    In SWIFT 3 : questo è il lavoro per me

        if let clearButton = self.textField.value(forKey: "_clearButton") as? UIButton {
            //Create a template copy of the original button image
            let templateImage =  clearButton.imageView?.image?.withRenderingMode(.alwaysTemplate)
    
            //Set the template image copy as the button image
            clearButton.setImage(templateImage, for: .normal)
            clearButton.setImage(templateImage, for: .highlighted)
    
            //Finally, set the image color
            clearButton.tintColor = .white
        }
  14. 1

    Risposta inviato da matt sopra è corretto. Il pulsante cancella all’interno UITextField non esiste se non indicato. Si può tentare di accedere subito dopo UITextField svolge la sua layoutSubviews e controllare l’esistenza del pulsante.
    L’approccio più semplice è quello di creare una sottoclasse di un UITextField, ignorare layoutSubviews e se il pulsante viene mostrato per la prima volta, il negozio è immagine originale(s) per un uso successivo, e poi durante le eventuali successive show-ups applicare una tinta.

    Di seguito vi mostro come eseguire questa operazione utilizzando l’estensione, perché in questo modo si è in grado di applicare la vostra abitudine di tinta per qualsiasi UITextField, compresi quelli annidati in pronta classi come UISearchBar.

    Divertirsi e dare pollici in su se vi piace 🙂

    Swift 3.2

    Qui è il principale estensione:

    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()
        }
    
    }

    Qui ci sono ulteriori frammenti utilizzati nel codice sopra:

    Bel contenitore di roba a cui si desidera accedere oggetto-saggi:

    class Wrapper<T> {
        var underlying: T?
    
        init(_ underlying: T?) {
            self.underlying = underlying
        }
    }

    Una manciata di estensione per la ricerca di nidificati secondarie di qualsiasi tipo:

    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
        }
    
    }

    Estensione per UIImage per applicare una tinta di colore

    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
        }
    
    }

    …e infine Swizzling roba:

    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)
            }
        }
    
    }
  15. 1

    Swift 4, questo funziona per me (modifica la tintColor per il proprio colore):

    var didSetupWhiteTintColorForClearTextFieldButton = false
    
    private func setupTintColorForTextFieldClearButtonIfNeeded() {
        //Do it once only
        if didSetupWhiteTintColorForClearTextFieldButton { return }
    
        guard let button = yourTextField.value(forKey: "_clearButton") as? UIButton else { return }
        guard let icon = button.image(for: .normal)?.withRenderingMode(.alwaysTemplate) else { return }
        button.setImage(icon, for: .normal)
        button.tintColor = .white
        didSetupWhiteTintColorForClearTextFieldButton = true
    }
    
    override func viewDidLayoutSubviews() {
        super.viewDidLayoutSubviews()
        setupTintColorForTextFieldClearButtonIfNeeded()
    }

    Bisogno di chiamare in viewDidLayoutSubviews() in modo che si assicurarsi che si ottiene chiamato alla fine, perché ci sono diversi clearButtonMode situazioni (always, whileEditing, etc.). Credo che questi pulsanti vengono creati pigramente. Così chiamata in viewDidLoad() soprattutto non funzionano.

  16. 1

    Swift 4, pulito e conciso Sottoclasse

    import UIKit
    
    class CustomTextField: UITextField {
        override func layoutSubviews() {
            super.layoutSubviews()
            for view in subviews where view is UIButton {
                (view as! UIButton).setImage(<MY_UIIMAGE>, for: .normal)
            }
        }
    }
  17. 1

    L’idea è di ottenere il pulsante clear per chiave clearButton, poi ri-renderizzare l’immagine chiara e alwaysTemplate modalità.

    [Swift 4.2]
    Appena fatto un’estensione per UITextField qui:

    extension UITextField {
        var clearButton: UIButton? {
            return value(forKey: "clearButton") as? UIButton
        }
    
        var clearButtonTintColor: UIColor? {
            get {
                return clearButton?.tintColor
            }
            set {
                let image =  clearButton?.imageView?.image?.withRenderingMode(.alwaysTemplate)
                clearButton?.setImage(image, for: .normal)
                clearButton?.tintColor = newValue
            }
        }
    }

    Ma il problema di questa soluzione è il pulsante cancella l’immagine di nil al momento si sta chiamando per impostare il colore della tinta.

    Così per ogni uno è con RxSwift osservare l’immagine in chiaro pulsante.

    import RxSwift
    
    extension UITextField {
        var clearButton: UIButton? {
            return value(forKey: "clearButton") as? UIButton
        }
    
        var clearButtonTintColor: UIColor? {
            get {
                return clearButton?.tintColor
            }
            set {
                _ = rx.observe(UIImage.self, "clearButton.imageView.image")
                    .takeUntil(rx.deallocating)
                    .subscribe(onNext: { [weak self] _ in
                        let image = self?.clearButton?.imageView?.image?.withRenderingMode(.alwaysTemplate)
                        self?.clearButton?.setImage(image, for: .normal)
                    })
                clearButton?.tintColor = newValue
            }
        }
    }
  18. 0

    È possibile utilizzare la mia libreria LSCategories a che fare con una riga:

    [textField lsSetClearButtonWithColor:[UIColor redColor] mode:UITextFieldViewModeAlways];

    NON uso privato, di api, NON cerca originale UIButton in UITextField sottoview gerarchia e NON richiedono di creare una sottoclasse UITextField, come alcune altre risposte qui. Usa invece rightView proprietà per imitare il sistema pulsante cancella quindi non c’è bisogno di preoccuparsi che si smetterà di lavorare, in futuro, se Apple cambia qualcosa. Funziona in rapida anche.

  19. 0

    Creare questo metodo.

    func configureClearButtonColor() {
    
        guard let clearButton = textField.value(forKey: "_clearButton") as? UIButton else {
            return
        }
        let templateImage = clearButton.imageView?.image?.withRenderingMode(.alwaysTemplate)
        clearButton.setImage(templateImage, for: .normal)
        clearButton.setImage(templateImage, for: .highlighted)
        clearButton.tintColor = .white
    }

    E implementare la UITextFieldDelegate, al di textFieldDidEndEditing chiamare il metodo. Cambiare la vostra immagine prima di creare un po ‘ di testo.

    func textFieldDidEndEditing(_ textField: UITextField) {
        configureClearButtonColor()
    }
  20. 0

    Dettagli

    • Xcode Versione 10.1 (10B61)
    • Swift 4.2

    Soluzione

    import UIKit
    
    extension UISearchBar {
    
        func getTextField() -> UITextField? { return value(forKey: "searchField") as? UITextField }
    
        func setClearButton(color: UIColor) {
            getTextField()?.setClearButton(color: color)
        }
    }
    
    extension UITextField {
    
        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 = "txt"
                        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)
            }
        }
    
        func getClearButton() -> UIButton? { return value(forKey: "clearButton") as? UIButton }
    }

    Intero campione

    class ViewController: UIViewController {
    
        override func viewDidLoad() {
            super.viewDidLoad()
            let textField = UITextField(frame: CGRect(x: 20, y: 20, width: 200, height: 44))
            view.addSubview(textField)
            textField.backgroundColor = .lightGray
            textField.clearButtonMode = .always
            textField.setClearButton(color: .red)
    
            let searchBar = UISearchBar(frame: CGRect(x: 20, y: 80, width: 200, height: 44))
            view.addSubview(searchBar)
            searchBar.backgroundColor = .lightGray
            searchBar.setClearButton(color: .red)
        }
    }

    Risultato

    Come modificare la tonalità di colore del pulsante cancella in un UITextField

  21. 0

    Ho provato un sacco di risposte fino a trovare questa soluzione, in base a @Mikael Hellman soluzione. Questa soluzione è usare Swift 4.2.

    L’idea è la stessa:

    Non utilizza nessuna immagine personalizzata o aggiunta di pulsanti etc.

    E l’utilizzo di una classe personalizzata che si estende UITextField.

    class TintClearTextField: UITextField {
    
        private var updatedClearImage = false
    
        override func layoutSubviews() {
            super.layoutSubviews()
            tintClearImage()
        }
    
        private func tintClearImage() {
            if updatedClearImage { return }
    
            if let button = self.value(forKey: "clearButton") as? UIButton,
                let image = button.image(for: .highlighted)?.withRenderingMode(.alwaysTemplate) {
                button.setImage(image, for: .normal)
                button.setImage(image, for: .highlighted)
                button.tintColor = .white
    
                updatedClearImage = true
            }
        }
    }

    Non avete bisogno di un updatedClearImage, ma avere in mente che sarete esecuzione di tutte le logiche in ogni personaggio oltre.

    Non ho nemmeno bisogno di impostare il tintColor per ottenere il risultato che cercavo. Provare a commentare quella riga prima di impostare il vostro colore.

    Se non sembra che si desidera, modificare il .white con il colore desiderato, e questo è tutto.

    PS.: Ho un campo che è già inserito nella mia schermata iniziale, e per questo solo il cambiamento di colore con tintColor succede millisecondi dopo che l’elemento predefinito di colore, come un “glitch”. Non ho potuto fare di meglio, ma dal momento che io non sto usando l’ tintColor, che è ok per me.

    Speranza che aiuta 🙂

Lascia un commento