XCode Tips&Trick #8 – UIAlertView con colore di sfondo personalizzato

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.

Ingegnere informatico e sviluppatore freelance, mi occupo da anni di sviluppo per iOS (ma non solo). Dal 2008 scrivo su questo piccolo blog (con qualche lunga pausa), in cui parlo di programmazione e di qualsiasi altra cosa che mi diverta.

13 comments On XCode Tips&Trick #8 – UIAlertView con colore di sfondo personalizzato

Leave a reply:

Your email address will not be published.

Site Footer