Cómo evitar que UIButton parpadee al actualizar el título


85

Cuando llamo a setTitle en un UIButton, el botón parpadea en iOS 7. Intenté configurar myButton.highlights = NO, pero eso no impidió que el botón parpadeara.

[myButton setTitle:[[NSUserDefaults standardUserDefaults] stringForKey:@"elapsedLabelKey"] forState:UIControlStateNormal];

myButton.highlighted = NO;

Así es como configuro el temporizador que actualizó los títulos:

- (void)actionTimer {
    if (myTimer == nil) {

        myTimer = [NSTimer scheduledTimerWithTimeInterval: 1.0
                        target: self
                        selector: @selector(showActivity)
                        userInfo: nil
                        repeats: YES];
    }
}

Este es el método que realmente actualiza los títulos:

- (void)showActivity {

    NSString *sym = [[NSLocale currentLocale] objectForKey:NSLocaleCurrencySymbol];

    if (pauseInterval == nil) {

        // Update clock
        seconds = [[NSDate date] timeIntervalSinceDate:startInterval] - breakTime;

        // Update total earned
        secRate = rate.value / 60 / 60;
        total = secRate * seconds;
        [totalLabel setTitle:[NSString stringWithFormat:@"%@%.4f",sym,total] forState:UIControlStateNormal];

        days = seconds / (60 * 60 * 24);
        seconds -= days * (60 * 60 * 24);
        int hours = seconds / (60 * 60);
        fhours = (float)seconds / (60.0 * 60.0);
        seconds -= hours * (60 * 60);
        int minutes = seconds / 60;
        seconds -= minutes * 60;

        // Update the timer clock
        [elapsed setTitle:[NSString stringWithFormat:@"%.2i:%.2i:%.2i:%.2i",days,hours,minutes,seconds] forState:UIControlStateNormal];
    }
}

No debería estar parpadeando. ¿Estás intentando hacer esto en un hilo de fondo?
— BergQuester

Sí, se está configurando en un temporizador para actualizar el título del botón cada segundo (que creo que crea su propio hilo)
— FierceMonkey

Los temporizadores solo se ejecutan en un hilo separado si los configura para hacerlo. ¿Podríamos ver el método en el que se actualiza el título y cómo configura el temporizador?
— BergQuester


Respuestas:


205

Establezca el tipo de botón en UIButtonTypeCustom y dejará de parpadear


16
Esta debería ser realmente la respuesta preferida. La solucion mas sencilla. Y está funcionando.
— Johan Karlsson

4
Convenido. Probé muchas otras soluciones y esto es lo que lo hizo, por sí solo.
— BBQ Steve

2
Esta debería ser la respuesta aceptada. La solución más sencilla hasta ahora.
— Machado

1
¡Funciona de maravilla! Gracias

2
Creo que esta es una solución realmente buena sin escribir ningún código para eso.
— Chauyan

55

Un enfoque mejor que el [UIView setAnimationsEnabled:NO]que puede afectar a otras animaciones es deshabilitar solo la animación del título específico.

C objetivo:

[UIView performWithoutAnimation:^{
  [myButton setTitle:text forState:UIControlStateNormal];
  [myButton layoutIfNeeded];
}];

Rápido:

UIView.performWithoutAnimation { 
    myButton.setTitle(text, for: .normal)
    myButton.layoutIfNeeded()
}

Acabo de probar la solución Swift en el último iOS: funciona muy bien.
— Ronen Rabinovici

1
Salvador del día. ¡Salud!
— pkc456

Intenté esto en Swift 3, y funciona sin el uso de layoutIfNeeded ()
— user1898712

3
¡Esta debería ser la respuesta aceptada sin lugar a dudas!
— Julius

1
Esta es la mejor forma de hacer esto. ¡Gran respuesta!
— Ascender

29

* Tenga en cuenta *

cuando " buttonType " de _button es "UIButtonTypeSystem" , el código siguiente no es válido :

[UIView setAnimationsEnabled:NO];
[_button setTitle:@"title" forState:UIControlStateNormal];
[UIView setAnimationsEnabled:YES];

cuando " buttonType " de _button es "UIButtonTypeCustom" , el código anterior es válido .


19

Vea las respuestas de ¿Cómo detener la animación UIButton no deseada en el cambio de título? :

[UIView setAnimationsEnabled:NO];
[elapsed setTitle:[NSString stringWithFormat:@"%.2i:%.2i:%.2i:%.2i",days,hours,minutes,seconds] forState:UIControlStateNormal];
[UIView setAnimationsEnabled:YES];

7
@FierceMonkey trate de añadir una llamada a layoutIfNeeded: [elapsed layoutIfNeeded];. Esto eliminó el parpadeo en mi caso.
— Klaas

1
layoutIfNeeded lo hizo por mí.
— Kaolin Fire

Parece ser una solución bastante sucia, sin embargo layoutIfNeeded, parece estar funcionando
— Przemysław Wrzesiński

7

Simplemente puede crear otra función para UIButton para facilitar el uso futuro.

extension UIButton {
    func setTitleWithoutAnimation(_ title: String?, for controlState: UIControlState) {
        UIView.performWithoutAnimation {
            self.setTitle(title, for: controlState)
            self.layoutIfNeeded()
        }
    }
}

¡Eso es!

Y simplemente establezca el título como lo haría antes, pero reemplácelo setTitleconsetTitleWithoutAnimation


6

¡El comportamiento predeterminado de "setTitle" es definitivamente odioso!

Mi solucion es:

[UIView setAnimationsEnabled:NO];
[_button layoutIfNeeded]; 
[_button setTitle:[NSString stringWithFormat:@"what" forState:UIControlStateNormal];
[UIView setAnimationsEnabled:YES];

Además, en el guión gráfico, en la propiedad del botón desmarco:

  • Invierte en resaltado
  • Imagen de ajuste resaltada

Y comprobar:

  • Desactivado Ajustar imagen

Probado y funcionando también en iOS 8 .

Actualización - Swift

Le sugiero que cree su botón personalizado y anule el método setTitle .

class UnflashingButton: UIButton {
   
    override func setTitle(title: String?, forState state: UIControlState) {
        UIView.setAnimationsEnabled(false)
        self.layoutIfNeeded()
        super.setTitle(title, forState: state)
        UIView.setAnimationsEnabled(true)
    }

}

Probé este enfoque (subclasificación, anulando setTitle: forState: y deshabilitando-habilitando UIView.setAnimationsEnabled). No me funciona en iOS 9 y 10 beta. Funciona si solo desactivo las animaciones, pero luego se pierden para cada UIView ...
— cdf1982

2

Pruebe esto, esto funciona en las versiones más recientes de IOS:

class CustomButtonWithNoEffect : UIButton {
    override func setTitle(_ title: String?, for state: UIControlState) {
        UIView.performWithoutAnimation {
            super.setTitle(title, for: state)
            super.layoutIfNeeded()
        }
    }

}

0

Soy nuevo en codificación y Stackoverflow, así que no tengo suficiente reputación para comentar directamente para expandir https://stackoverflow.com/users/4673064/daniel-tseng excelente respuesta. Entonces tengo que escribir mi propia respuesta nueva, y es esta:

extension UIButton {
    func setTitleWithoutAnimation(_ title: String?, for controlState: UIControlState) {
        UIView.performWithoutAnimation {
            self.setTitle(title, for: controlState)
            self.layoutIfNeeded()
        }
    }
}

Funciona muy bien, EXCEPTO:

Si todas mis llamadas más adelante en el código a "setTitleWithoutAnimation" no especifican un remitente, entonces recibo estos mensajes extraños relacionados con CoreMedia o CoreData, por ejemplo, "No se pudieron heredar los permisos de CoreMedia de 2526: (nulo)"

Esto es probablemente bastante básico para la codificación y iOS, pero para mí, como nuevo codificador, me envió por un camino de conejo por un tiempo, como en: Today Extension No se pudieron heredar los permisos de CoreMedia , donde la gente tenía respuestas interesantes pero eso NO llegar a la raíz de mi problema.

Así que finalmente descubrí que tenía que revisar y dar parámetros a mis funciones sin parámetros, es decir, tenía que especificar un remitente. Ese remitente podría ser UIButton, Any o AnyObject. Todos funcionaron, pero en última instancia parece haber un conflicto entre agregar una extensión de botón con "self" y no decir específicamente más adelante que un botón la está usando.

Nuevamente, probablemente básico, pero nuevo para mí, así que pensé que valdría la pena compartirlo.


0

Otro truco

@IBOutlet private weak var button: UIButton! {
    didSet {
        button.setTitle(title, for: .normal)
    }
}

Esto solo funciona si conoce el valor del título sin realizar ninguna llamada a la API. El título del botón se establecerá antes de que se cargue la vista, por lo que no verá la animación.

Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.