Eccoci ancora una volta con un piccolo tip sulle UIAlertView. Questi sono sicuramente tra i componenti più utilizzati e anche più versatili, ma non è facile cambiarne l’aspetto grafico.
Può capitare, infatti, che la classica UIAlertView “stoni” con il design della nostra applicazione, rendendo il tutto un po’ meno piacevole. Personalizzarne il colore e lo stile non è facile ed immediato, ma ho trovato su Internet una classe che permette di creare delle alert con colori personalizzati, semplificandoci davvero il lavoro!
Eccovi un esempio di ciò che tale classe permette di fare:
Per implementare questo componente create una nuova classe di nome “CustomAlert” e inserite nel file .h questo codice:
#import
@interface CustomAlert : UIAlertView{
}
+ (void)setBackgroundColor:(UIColor *)background withStrokeColor:(UIColor *) stroke;
@end
e nel file .m questo codice:
#import "CustomAlert.h"
@interface CustomAlert (Private)
- (void) drawRoundedRect:(CGRect) rect inContext:(CGContextRef)
context withRadius:(CGFloat) radius;
@end
static UIColor *fillColor = nil;
static UIColor *borderColor = nil;
@implementation CustomAlert
+ (void) setBackgroundColor:(UIColor *) background
withStrokeColor:(UIColor *) stroke
{
if(fillColor != nil)
{
[fillColor release];
[borderColor release];
}
fillColor = [background retain];
borderColor = [stroke retain];
}
- (id)initWithFrame:(CGRect)frame
{
if((self = [super initWithFrame:frame]))
{
if(fillColor == nil)
{
fillColor = [[UIColor blackColor] retain];
borderColor = [[UIColor colorWithHue:0.625
saturation:0.0 brightness:0.8 alpha:0.8]
retain];
}
}
return self;
}
- (void)layoutSubviews
{
for (UIView *sub in [self subviews])
{
if([sub class] == [UIImageView class] && sub.tag == 0)
{
// The alert background UIImageView tag is 0,
// if you are adding your own UIImageView's
// make sure your tags != 0 or this fix
// will remove your UIImageView's as well!
[sub removeFromSuperview];
break;
}
}
}
- (void)drawRect:(CGRect)rect
{
CGContextRef context = UIGraphicsGetCurrentContext();
CGContextClearRect(context, rect);
CGContextSetAllowsAntialiasing(context, true);
CGContextSetLineWidth(context, 0.0);
CGContextSetAlpha(context, 0.8);
CGContextSetLineWidth(context, 2.0);
CGContextSetStrokeColorWithColor(context, [borderColor CGColor]);
CGContextSetFillColorWithColor(context, [fillColor CGColor]);
// Draw background
CGFloat backOffset = 2;
CGRect backRect = CGRectMake(rect.origin.x + backOffset,
rect.origin.y + backOffset,
rect.size.width - backOffset*2,
rect.size.height - backOffset*2);
[self drawRoundedRect:backRect inContext:context withRadius:8];
CGContextDrawPath(context, kCGPathFillStroke);
// Clip Context
CGRect clipRect = CGRectMake(backRect.origin.x + backOffset-1,
backRect.origin.y + backOffset-1,
backRect.size.width - (backOffset-1)*2,
backRect.size.height - (backOffset-1)*2);
[self drawRoundedRect:clipRect inContext:context withRadius:8];
CGContextClip (context);
//Draw highlight
CGGradientRef glossGradient;
CGColorSpaceRef rgbColorspace;
size_t num_locations = 2;
CGFloat locations[2] = { 0.0, 1.0 };
CGFloat components[8] = { 1.0, 1.0, 1.0, 0.35, 1.0, 1.0, 1.0, 0.06 };
rgbColorspace = CGColorSpaceCreateDeviceRGB();
glossGradient = CGGradientCreateWithColorComponents(rgbColorspace,
components, locations, num_locations);
CGRect ovalRect = CGRectMake(-130, -115, (rect.size.width*2),
rect.size.width/2);
CGPoint start = CGPointMake(rect.origin.x, rect.origin.y);
CGPoint end = CGPointMake(rect.origin.x, rect.size.height/5);
CGContextSetAlpha(context, 1.0);
CGContextAddEllipseInRect(context, ovalRect);
CGContextClip (context);
CGContextDrawLinearGradient(context, glossGradient, start, end, 0);
CGGradientRelease(glossGradient);
CGColorSpaceRelease(rgbColorspace);
}
- (void) drawRoundedRect:(CGRect) rrect inContext:(CGContextRef) context
withRadius:(CGFloat) radius
{
CGContextBeginPath (context);
CGFloat minx = CGRectGetMinX(rrect), midx = CGRectGetMidX(rrect),
maxx = CGRectGetMaxX(rrect);
CGFloat miny = CGRectGetMinY(rrect), midy = CGRectGetMidY(rrect),
maxy = CGRectGetMaxY(rrect);
CGContextMoveToPoint(context, minx, midy);
CGContextAddArcToPoint(context, minx, miny, midx, miny, radius);
CGContextAddArcToPoint(context, maxx, miny, maxx, midy, radius);
CGContextAddArcToPoint(context, maxx, maxy, midx, maxy, radius);
CGContextAddArcToPoint(context, minx, maxy, minx, midy, radius);
CGContextClosePath(context);
}
- (void)dealloc
{
[super dealloc];
}
@end
Per utilizzare delle UIAlertView personalizzate dovrete utilizzare questa classe nello stesso modo in cui utilizzare gli alert tradizionali, eccovi un esempio:
// Imposto i colori
[CustomAlert setBackgroundColor:[UIColor blueColor] withStrokeColor:[UIColor cyanColor]];
// Creo e visualizzo l'alert personalizzata
CustomAlert *alert=[[CustomAlert alloc] initWithTitle:@"Prova!" message:@"Eccovi un'alert personalizzata.." delegate:self cancelButtonTitle:@"OK" otherButtonTitles:nil];
[alert show];
[alert release];
Questo è l’unico modo che ho trovato per personalizzare il colore di una UIAlertView, e devo dire che i risultati non sono male. Se siete a conoscenza di altri metodi fatemelo sapere nei commenti!
Aggiornamento 21/01/2011: il codice è stato aggiornato (come nella versione originale) per funzionare anche con iOS 4.2 😉
I meriti di tale classe sono di kwigbo, trovate l’articolo originale a questo indirizzo.
13 comments On XCode Tips&Trick #8 – UIAlertView con colore di sfondo personalizzato
Ciao,
il codice è interessante e può tornare utile.
Mi viene un dubbio però.
Non è che poi si vada contro le User Interface Gudelines e la Apple rifiuti l’app?
Ho poi un altro paio di dubbi riguardo il codice.
Perché il metodo setBackgroundColor:withStrokeColor: è dichiarato come metodo di classe?
E perché i puntatoti ai due colori fillColor e borderColor vengono dichiarati come statici al di fuori dell’interfaccia della classe?
E in ultimo, chi li rilascia poi quegli oggetti, dato che viene fatto il retain?
In pratica, non si poteva mettere i due colori come variabili d’istanza e usare il metodo come d’istanza?
Scusa l’ignoranza, ma non riuscendo a capire bene la cosa volevo maggiori deluciadzioni.
Grazie!
grazie
Bella questa !
Grazie Andrea !
Mi capita proprio a fagiolo per la mia app
@Fast: prego 😉
@FM: perchè “setBackgroundColor:withStrokeColor” sia definito statico non l’ho ben capito nemmeno io, si sarebbe potuto fare un metodo d’istanza classico.. io ho trovato l’esempio così, se riuscite ad apportare miglioramenti aggiorno l’articolo 😉
P.S: anche il creatore della classe sul suo blog ha detto che non è perfetta, quindi penso si possa migliorare in qualche aspetto 😉
Intanto ringrazio per la guida , in volevo comunicare che ho utilizzato la guida nella mia app che è stata appena approvata , quindi sembra non ci siano problemi con le UIG !
@Ragazzetto: ottimo, grazie mille della conferma 😉
Prego !
🙂
Aggiorno !
Con il 4.2 beta la classe non funziona più correttamente , ci sono problemi di visualizzazione !
@Ragazzetto: grazie della segnalazione! proverò a darci un’occhiata! 😉
Andrea hai mica avuto modo di darci l’ occhiata ?
Intanto ti posso dire che è stato aggiunto un messaggio anche sull articolo di kwigbo per cumunicargli il mal funzionamento !
E’ arrivata la soluzione dall autore !!!!!
http://kwigbo.com/post/318396305/iphone-sdk-custom-uialertview-background-color
@Ragazzetto: ottimo!! provo a guardarci e nel caso aggiorno l’articolo 😉
Articolo aggiornato, ora il codice è compatibile anche con iOS 4.2 😉 (testato su simulatore, funziona senza problemi)