ios - alert swift 4
¿Cómo cambiar el color del texto del botón UIAlertController en iOS9? (13)
La pregunta es similar al color de texto de los botones UIActivityViewController y UIAlertController de iOS 8 que usa el color tintColor de la ventana pero en iOS 9.
Tengo un UIAlertController y el botón de despedir mantiene el color blanco incluso cuando he intentado configurar
[[UIView appearanceWhenContainedIn:[UIAlertController class], nil] setTintColor:[UIColor blackColor]];
UIAlertController *strongController = [UIAlertController alertControllerWithTitle:title
message:message
preferredStyle:preferredStyle];
strongController.view.tintColor = [UIColor black];
En Swift 2.2 puedes usar el siguiente código
// LogOut or Cancel
let logOutActionSheet: UIAlertController = UIAlertController(title: "Hello Mohsin!", message: "Are you sure you want to logout?", preferredStyle: .Alert)
self.presentViewController(logOutActionSheet, animated: true, completion: nil)
let cancelActionButton: UIAlertAction = UIAlertAction(title: "Cancel", style: .Cancel) { action -> Void in
print("Cancel Tapped")
}
logOutActionSheet.addAction(cancelActionButton)
let logOutActionButton: UIAlertAction = UIAlertAction(title: "Clear All", style: .Default)
{ action -> Void in
//Clear All Method
print("Logout Tapped")
}
logOutActionButton.setValue(UIColor.redColor(), forKey: "titleTextColor")
logOutActionSheet.addAction(logOutActionButton)
Encontré una solución a esto. No es una solución elegante, sino una solución.
Revolví la vista. Aparecerá: en UIAlertController, luego repasé las vistas y modifiqué el color del tinte. En mi caso, tenía un tintColor configurado en toda la ventana y, a pesar de haber configurado tintColor a través de la apariencia, el controlador UIAlert mantuvo el color en la ventana. Verifico si el color es igual al de la ventana y si es así aplico uno nuevo. Si aplica ciegamente el color tint a todas las vistas, se restablecerá el tinte rojo de las acciones destructivas.
+ (void)load
{
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
Method swizzleMethod = class_getInstanceMethod(self, @selector(viewWillAppear:));
Method method = class_getInstanceMethod(self, @selector(alertSwizzle_viewWillAppear:));
method_exchangeImplementations(method, swizzleMethod);
});
}
- (void)alertSwizzle_viewWillAppear:(BOOL)animated
{
[self alertSwizzle_viewWillAppear:animated];
[self applyTintToView:self.view];
}
- (void)applyTintToView:(UIView *)view
{
UIWindow *mainWindow = [UIApplication sharedApplication].keyWindow;
for (UIView *v in view.subviews) {
if ([v.tintColor isEqual:mainWindow.tintColor]) {
v.tintColor = [UIColor greenColor];
}
[self applyTintToView:v];
}
}
Sin embargo, esto no funciona en iOS 8, por lo que aún tendrá que establecer el color del tinte de apariencia.
[[UIView appearanceWhenContainedIn:[UIAlertController class], nil] setTintColor:[UIColor greenColor]];
Hay un problema con la configuración del color del tinte en la vista después de la presentación; incluso si lo hace en el bloque de finalización de presentViewController: animated: completed :, se produce un efecto de parpadeo en el color de los títulos de los botones. Esto es descuidado, no profesional y completamente inaceptable.
La única manera segura de resolver este problema y hacerlo en cualquier lugar, es mediante la adición de una categoría a UIAlertController y la visualización de la vista.
El encabezado:
//
// UIAlertController+iOS9TintFix.h
//
// Created by Flor, Daniel J on 11/2/15.
//
#import <UIKit/UIKit.h>
@interface UIAlertController (iOS9TintFix)
+ (void)tintFix;
- (void)swizzledViewWillAppear:(BOOL)animated;
@end
La implementación:
//
// UIAlertController+iOS9TintFix.m
//
// Created by Flor, Daniel J on 11/2/15.
//
#import "UIAlertController+iOS9TintFix.h"
#import <objc/runtime.h>
@implementation UIAlertController (iOS9TintFix)
+ (void)tintFix {
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
Method method = class_getInstanceMethod(self, @selector(viewWillAppear:));
Method swizzle = class_getInstanceMethod(self, @selector(swizzledViewWillAppear:));
method_exchangeImplementations(method, swizzle);});
}
- (void)swizzledViewWillAppear:(BOOL)animated {
[self swizzledViewWillAppear:animated];
for (UIView *view in self.view.subviews) {
if (view.tintColor == self.view.tintColor) {
//only do those that match the main view, so we don''t strip the red-tint from destructive buttons.
self.view.tintColor = [UIColor colorWithRed:0.0 green:122.0/255.0 blue:1.0 alpha:1.0];
[view setNeedsDisplay];
}
}
}
@end
Agregue un .pch (encabezado precompilado) a su proyecto e incluya la categoría:
#import "UIAlertController+iOS9TintFix.h"
Asegúrese de registrar su pch en el proyecto correctamente, e incluirá los métodos de categoría en cada clase que use el UIAlertController.
Luego, en su aplicación, los delegados hicieron el método de Finalización de Lanzamientos Finales, importan su categoría y llaman
[UIAlertController tintFix];
y se propagará automáticamente a cada instancia única de UIAlertController dentro de su aplicación, ya sea lanzada por su código o la de cualquier otra persona.
Esta solución funciona tanto para iOS 8.X como para iOS 9.X y carece del parpadeo del enfoque posterior a la presentación de tint change.
Gracias a Madon por el inicio de este viaje, desafortunadamente mi reputación no fue suficiente para comentar sobre su publicación, ¡o de lo contrario la habría dejado allí!
La forma más razonable es configurar tintColor de la ventana principal. Como una apariencia uniforme es lo que usualmente necesitamos.
// in app delegate
window.tintColor = ...
Otras soluciones tienen defectos.
Usar apariencia
UIView.appearance(whenContainedInInstancesOf: [UIAlertController.self]).tintColor = ...
No funciona en iOS 9, pruebas con iOS 11 SDK.
[[UIView appearance] setTintColor:[UIColor black]];
¿En serio?
Establecer el tintColor de la vista UIAlertController es inestable. El color puede cambiar cuando el usuario presiona el botón o después de ver el diseño.
Subclase UIAlertController y el método de diseño de sobrescritura es una forma de hackeo que es inaceptable.
Me he encontrado con algo similar en el pasado y el problema parece deberse al hecho de que la vista del controlador de alerta no está lista para aceptar los cambios de tintColor
antes de que se presenten. Alternativamente, intente configurar el color del tinte DESPUÉS de presentar su controlador de alerta:
[self presentViewController:strongController animated:YES completion:nil];
strongController.view.tintColor = [UIColor black];
Pude resolver esto mediante la subclasificación de UIAlertController
:
class MyUIAlertController: UIAlertController {
override func viewWillLayoutSubviews() {
super.viewWillLayoutSubviews()
//set this to whatever color you like...
self.view.tintColor = UIColor.blackColor()
}
}
Esto sobrevive a una rotación del dispositivo mientras se muestra la alerta.
Tampoco es necesario configurar el tintColor después de presentar la alerta al usar esta subclase.
Aunque no es necesario en iOS 8.4, este código también funciona en iOS 8.4.
La implementación de Objective-C debería ser algo como esto:
@interface MyUIAlertController : UIAlertController
@end
@implementation MyUIAlertController
-(void)viewWillLayoutSubviews {
[super viewWillLayoutSubviews];
//set this to whatever color you like...
self.view.tintColor = [UIColor blackColor];
}
@end
Puedes cambiarlo usando: Swift 3.x
strongController.view.tintColor = UIColor.green
Quería hacer que el botón Eliminar apareciera en rojo, así que usé el estilo destructivo:
alert.addAction(UIAlertAction(title: "Delete", style: .destructive, handler:{(UIAlertAction) in
Tienes 3 estilos para los botones de acción:
let style : UIAlertActionStyle = .default
// default, cancel (bold) or destructive (red)
let alertCtrl = UIAlertController(....)
alertCtrl.addAction( UIAlertAction(title: "click me", style: style, handler: {
_ in doWhatever()
}))
C objetivo
UIAlertController *alertController = [UIAlertController alertControllerWithTitle:@"Title text" message:@"Message text" preferredStyle:UIAlertControllerStyleAlert];
UIAlertAction* ok = [UIAlertAction actionWithTitle:@"Yes" style:UIAlertActionStyleDefault handler:^(UIAlertAction * action) {
//code here…
}];
UIAlertAction* cancel = [UIAlertAction actionWithTitle:@"Later" style:UIAlertActionStyleDefault handler:^(UIAlertAction * action) {
//code here….
}];
[ok setValue:[UIColor greenColor] forKey:@"titleTextColor"];
[cancel setValue:[UIColor redColor] forKey:@"titleTextColor"];
[alertController addAction:ok];
[alertController addAction:cancel];
[alertController.view setTintColor:[UIColor yellowColor]];
[self presentViewController:alertController animated:YES completion:nil];
Swift 3
let alertController = UIAlertController(title: "Title text", message: "Message text", preferredStyle: .alert)
let ok = UIAlertAction(title: "Yes" , style: .default) { (_ action) in
//code here…
}
let cancel = UIAlertAction(title: "Later" , style: .default) { (_ action) in
//code here…
}
ok.setValue(UIColor.green, forKey: "titleTextColor")
cancel.setValue(UIColor.red, forKey: "titleTextColor")
alertController.addAction(ok)
alertController.addAction(cancel)
alertController.view.tintColor = .yellow
self.present(alertController, animated: true, completion: nil)
En Swift 3.x:
Encontré lo siguiente para trabajar efectivamente. Llamo a esto en el lanzamiento de la aplicación.
UIView.appearance(whenContainedInInstancesOf: [UIAlertController.self]).tintColor = UIColor.black
Por lo tanto, esto cambiaría el color del tinte de todas las etiquetas de botones de UIAlertViewController en su aplicación globalmente. El único color de la etiqueta del botón que no cambia son aquellos que tienen un estilo UIAlertAction de estilo destructivo.
swift3
Se intentó utilizar UIView.appearance(whenContainedInInstancesOf: [UIAlertController.self]).tintColor = MyColor
pero esto impide que otros elementos no relacionados con UIAlertController
de la configuración de tintColor. Lo vi mientras intentaba cambiar el color de los elementos de los botones de la barra de navegación.
Cambié a una extensión (según la respuesta de Mike Taverne anterior) y funciona muy bien.
extension UIAlertController {
override open func viewWillLayoutSubviews() {
super.viewWillLayoutSubviews()
//set this to whatever color you like...
self.view.tintColor = MyColor
}
}
[[UIView appearance] setTintColor:[UIColor black]];
esto cambiará todo el UIView tintColor
así como la vista de UIAlertController