Класс UIAlertView прост в реализации, но если вы не попадаете под капот и не возитесь с ним, он будет каждый раз выглядеть одинаково.  Этот краткий совет показывает, как создавать собственные графические изображения программно и применять их к предупреждению.  Изменение графики в вашем приложении может быть просто залогом нового и привлекательного дизайна! 
Шаг 1: настройте файл Xcode
  Запустите Xcode и создайте новый проект, щелкнув Файл> Новый> Новый проект.  Мы хотим создать 
  iOS пустое приложение.  Назовите ваш продукт «Custom Alert» и введите идентификатор компании по вашему выбору.  Выберите «iPhone» в меню «Семейство устройств» и удалите все проверки перед «Использовать базовые данные», «Использовать автоматический подсчет ссылок» и «Включить юнит-тесты».  Нажмите «Далее» и выберите место для сохранения вашего проекта.  Убедитесь, что поле рядом с «Source Control» не отмечено и нажмите «Создать», чтобы создать проект. 

Шаг 2. Создайте UIAlertView.
  Сначала мы хотим UIAlertView подкласс UIAlertView .  Нажмите Файл> Новый> Новый файл, чтобы создать новый подкласс.  Выберите класс iOS Cocoa Touch Objective-C и нажмите «Далее».  Назовите свой класс «CustomAlertView.»  и выберите UIView из меню «Подкласс».  Прежде чем нажать «Далее», выберите папку «CustomAlert» в меню «Группы» и убедитесь, что «CustomAlert» отмечен в поле «Цели».  Нажмите «Создать», чтобы добавить новый подкласс. 
  Недавно созданный класс является классом UIView , но он нам нужен для наследования от UIAlertView .  Нажмите на файл «CustomAlertView.h» и измените наследование на UIAlertView . 
| 
 1 
2 
3 
4 
5 
 | 
 #import <UIKit/UIKit.h> 
@interface CustomAlertView : UIAlertView 
@end 
 | 
  В заголовочном файле AppDelegate импортируйте файл «CustomAlertView.h» и выполните протокол UIAlertViewDelegate . 
| 
 1 
2 
3 
4 
5 
6 
7 
 | 
 #import <UIKit/UIKit.h> 
#import «CustomAlertView.h» 
@interface AppDelegate : UIResponder <UIApplicationDelegate, UIAlertViewDelegate> 
@property (strong, nonatomic) UIWindow *window; 
@end 
 | 
  Перейдите к файлу реализации AppDelegate и alertView:clickedButtonAtIndex: метод экземпляра alertView:clickedButtonAtIndex: 
  buttonIndex используется для определения, какая кнопка была нажата. 
| 
 1 
2 
3 
4 
5 
6 
7 
8 
9 
 | 
 — (void)alertView:(UIAlertView *)alertView clickedButtonAtIndex:(NSInteger)buttonIndex 
{ 
    if (buttonIndex == 0) { 
        NSLog(@»THE ‘NO’ BUTTON WAS PRESSED»); 
    } 
    if (buttonIndex == 1) { 
        NSLog(@»THE ‘YES’ BUTTON WAS PRESSED»); 
    } 
} 
 | 
  Теперь вставьте следующий код для создания экземпляра объекта оповещения в application:didFinishLaunchingWithOptions: method. 
  Обратите внимание, что для делегата установлено значение self в методе init , чтобы получить обратный вызов при нажатии кнопки. 
| 
 1 
2 
3 
4 
5 
6 
7 
 | 
 CustomAlertView *customAlertView = [[CustomAlertView alloc] initWithTitle:@»Custom Alert View» 
                                                            message:@»Customize the look of your app’s alert view programmatically.» 
                                                            delegate:self 
                                               cancelButtonTitle:@»NO» 
                                               otherButtonTitles:@»YES»,nil]; 
[customAlertView show]; 
[customAlertView release]; 
 | 
  Если вы создадите и запустите приложение прямо сейчас, вы получите типичную графику стандартного UIAlertView . 
Шаг 3: настроить графику
  Давайте удалим стандартную графику и UIAlertView . 
Переопределение макета Subviews:
  Во-первых, нам нужно переопределить layoutSubviews layoutSubviews: метод UIView в файле «CustomAlertView.m», где мы скроем синий фон и найдем метки, чтобы изменить внешний вид текста. 
| 
 01 
02 
03 
04 
05 
06 
07 
08 
09 
10 
11 
12 
13 
14 
15 
 | 
 — (void)layoutSubviews 
{ 
    for (UIView *subview in self.subviews){ //Fast Enumeration 
        if ([subview isMemberOfClass:[UIImageView class]]) { 
            subview.hidden = YES; 
        } 
             if ([subview isMemberOfClass:[UILabel class]]) { //Point to UILabels To Change Text 
            UILabel *label = (UILabel*)subview; 
            label.textColor = [UIColor colorWithRed:210.0f/255.0f green:210.0f/255.0f blue:210.0f/255.0f alpha:1.0f]; 
            label.shadowColor = [UIColor blackColor]; 
            label.shadowOffset = CGSizeMake(0.0f, 1.0f); 
        } 
    } 
} 
 | 
  Поскольку layoutSubviews: вызывается после инициализации объекта, но перед layoutSubviews: объекта, у вас есть возможность добавить код, который обеспечит дополнительную настройку, прежде чем он появится на экране.  В приведенном выше коде мы используем быстрое перечисление для перебора массива существующих подпредставлений оповещения в поисках UIImageView , который содержит фон и две UILabels которые содержат текст.  Используя isMemberOfClass: метод isMemberOfClass: логическое значение true или false в зависимости от того, является ли подпредставление экземпляром указанного класса.  Когда классы расположены, UIImageView скрыт и установлены UILabels' текста UILabels' цвета теней и смещения теней. 
Переопределение drawRect
  Импорт готовой векторной графики может быть проблематичным.  Между изменением разрешения экрана и организацией файлов импорт изображений, как правило, требует больше усилий, чем в некоторых случаях.  Если вы ищете гибкую, идеальную по пикселям графику, лучше всего переопределить представление drawRect: метод. 
  Графика для UIAlertView созданная с помощью следующего кода, обеспечивает тонкую разницу в цвете, тени и текстуре, но сохраняет ту же общую форму стандартного оповещения.  Вставьте разделы кода, описанные в этом руководстве, в drawRect: метод в подклассе UIAlertView . 
Получить ссылку на текущий графический контекст
| 
 1 
 | 
 CGContextRef context = UIGraphicsGetCurrentContext(); 
 | 
  Функция UIGraphicsGetCurrentContext() возвращает ссылку на графический контекст текущего представления, позволяя вносить изменения в его состояние. 
Создать базовую форму
| 
 01 
02 
03 
04 
05 
06 
07 
08 
09 
10 
 | 
 CGRect activeBounds = self.bounds; 
CGFloat cornerRadius = 10.0f; 
CGFloat inset = 6.5f; 
CGFloat originX = activeBounds.origin.x + inset; 
CGFloat originY = activeBounds.origin.y + inset; 
CGFloat width = activeBounds.size.width — (inset*2.0f); 
CGFloat height = activeBounds.size.height — (inset*2.0f); 
CGRect bPathFrame = CGRectMake(originX, originY, width, height); 
CGPathRef path = [UIBezierPath bezierPathWithRoundedRect:bPathFrame cornerRadius:cornerRadius].CGPath; 
 | 
  Мы начнем с создания базовой формы с закругленными углами.  Обратите внимание, что параметры для формы основаны на текущих границах UIAlertView .  Это позволяет рисовать фигуру в соответствии с границами оповещения, компенсируя любые возникающие изменения.  При создании этой фигуры важны два компонента: cornerRadius и cornerRadius .  cornerRadius определяет округлость углов, в то время как inset определяет, как далеко внутри границ нарисована фигура.  Наконец, мы создаем фигуру с помощью UIBezierPath из bezierPathWithRoundedRect: cornerRadius: метода bezierPathWithRoundedRect: cornerRadius: 
  Доступ к свойству CGPath вновь созданного объекта UIBezierPath позволяет использовать его в контексте. 
Добавить заливку и внешнюю тень
| 
 1 
2 
3 
4 
 | 
 CGContextAddPath(context, path); 
CGContextSetFillColorWithColor(context, [UIColor colorWithRed:210.0f/255.0f green:210.0f/255.0f blue:210.0f/255.0f alpha:1.0f].CGColor); 
CGContextSetShadowWithColor(context, CGSizeMake(0.0f, 1.0f), 6.0f, [UIColor colorWithRed:0.0f/255.0f green:0.0f/255.0f blue:0.0f/255.0f alpha:1.0f].CGColor); 
CGContextDrawPath(context, kCGPathFill); 
 | 
  Когда рисуете в Core Graphics, думайте о слоях, накладываемых друг на друга.  В этом проекте первый слой состоит из теней, поскольку они являются самым нижним и внешним слоями.  Мы устанавливаем параметры первого графического состояния, в частности его форму, цвет заливки и цвет тени.  Затем мы рисуем контекст, используя CGContextDrawPath() и CGPathDrawingMode kCGPathFill которые по существу создадут внешнюю тень. 
Клип контекст
| 
 1 
2 
3 
 | 
 CGContextSaveGState(context); 
CGContextAddPath(context, path); 
CGContextClip(context); 
 | 
  Теперь мы хотим нарисовать внутри базовой формы.  Для этого нам нужно обрезать контекст по фигуре до рисования следующего состояния.  Все, что нарисовано позже, но перед вызовом CGContextRestoreGState() остается в области отсечения и не покрывает внешнюю тень. 
Рисовать градиент
| 
 01 
02 
03 
04 
05 
06 
07 
08 
09 
10 
11 
12 
13 
14 
15 
 | 
 CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB(); 
size_t count = 3; 
CGFloat locations[3] = {0.0f, 0.57f, 1.0f}; 
CGFloat components[12] = 
    { 
        70.0f/255.0f, 70.0f/255.0f, 70.0f/255.0f, 1.0f, //1 
        55.0f/255.0f, 55.0f/255.0f, 55.0f/255.0f, 1.0f, //2 
        40.0f/255.0f, 40.0f/255.0f, 40.0f/255.0f, 1.0f //3 
    }; 
CGGradientRef gradient = CGGradientCreateWithColorComponents(colorSpace, components, locations, count); 
CGPoint startPoint = CGPointMake(activeBounds.size.width * 0.5f, 0.0f); 
CGPoint endPoint = CGPointMake(activeBounds.size.width * 0.5f, activeBounds.size.height); 
CGContextDrawLinearGradient(context, gradient, startPoint, endPoint, 0); 
CGColorSpaceRelease(colorSpace); 
CGGradientRelease(gradient); 
 | 
  Далее мы добавляем тонкий градиент к фону.  Чтобы нарисовать градиент, нам понадобится ссылка на градиент, которая определяет цвета и их расположение в градиенте.  startPoint endPoint и endPoint градиента основаны на границах представления предупреждений, охватывающих все предупреждения, не выходя за пределы области отсечения.  Обратите внимание, что мы выпустили CGColorSpaceRef и CGGradientRef теперь, когда мы закончили с ними.  В общем, когда вы видите вызов функции Core Graphics со словом & quotcreate & quot в нем, вам нужно освободить ссылку, когда вы закончите. 
Создать заштрихованный фон
| 
 01 
02 
03 
04 
05 
06 
07 
08 
09 
10 
11 
12 
13 
14 
15 
16 
17 
18 
19 
20 
 | 
 CGFloat buttonOffset = 92.5f; 
CGContextSaveGState(context); 
CGRect hatchFrame = CGRectMake(0.0f, buttonOffset, activeBounds.size.width, (activeBounds.size.height — buttonOffset+1.0f)); 
CGContextClipToRect(context, hatchFrame); 
CGFloat spacer = 4.0f; 
int rows = (activeBounds.size.width + activeBounds.size.height/spacer); 
CGFloat padding = 0.0f; 
CGMutablePathRef hatchPath = CGPathCreateMutable(); 
for(int i=1; i<=rows; i++) { 
    CGPathMoveToPoint(hatchPath, NULL, spacer * i, padding); 
    CGPathAddLineToPoint(hatchPath, NULL, padding, spacer * i); 
} 
CGContextAddPath(context, hatchPath); 
CGPathRelease(hatchPath); 
CGContextSetLineWidth(context, 1.0f); 
CGContextSetLineCap(context, kCGLineCapRound); 
CGContextSetStrokeColorWithColor(context, [UIColor colorWithRed:0.0f/255.0f green:0.0f/255.0f blue:0.0f/255.0f alpha:0.15f].CGColor); 
CGContextDrawPath(context, kCGPathStroke); 
CGContextRestoreGState(context); 
 | 
  Следующий фрагмент кода касается заштрихованных диагональных линий за кнопками.  Чтобы линии рисовались только под кнопками, нам нужно создать новую форму прямоугольника, обрезать контекст для прямоугольника и добавить заштрихованные линии в контекст.  buttonOffset — это высота пространства для заштрихованных линий.  Шаблон движения, созданный циклом for основан на границах представления предупреждения.  Чтобы изменить внешний вид заштрихованных линий, просто CGContextSetLineWidth() spacer CGContextSetLineWidth() или значения hatchFrame . 
Нарисуйте разделительную линию
| 
 01 
02 
03 
04 
05 
06 
07 
08 
09 
10 
11 
12 
 | 
 CGMutablePathRef linePath = CGPathCreateMutable(); 
CGFloat linePathY = (buttonOffset — 1.0f); 
CGPathMoveToPoint(linePath, NULL, 0.0f, linePathY); 
CGPathAddLineToPoint(linePath, NULL, activeBounds.size.width, linePathY); 
CGContextAddPath(context, linePath); 
CGPathRelease(linePath); 
CGContextSetLineWidth(context, 1.0f); 
CGContextSaveGState(context); 
CGContextSetStrokeColorWithColor(context, [UIColor colorWithRed:0.0f/255.0f green:0.0f/255.0f blue:0.0f/255.0f alpha:0.6f].CGColor); 
CGContextSetShadowWithColor(context, CGSizeMake(0.0f, 1.0f), 0.0f, [UIColor colorWithRed:255.0f/255.0f green:255.0f/255.0f blue:255.0f/255.0f alpha:0.2f].CGColor); 
CGContextDrawPath(context, kCGPathStroke); 
CGContextRestoreGState(context); 
 | 
  Теперь мы хотим нарисовать разделительную линию между кнопками и надписями.  Создание линии с использованием CGPathCreateMutable рисует ее с использованием указанных точек.  Расположение линии в представлении предупреждений основано на buttonOffset и охватывает ее ширину.  Еще раз, мы используем вызов функции, содержащий слово «create», CGPathCreateMutable() .  Поэтому мы выпускаем CGMutablePathRef один после того, как мы закончим. 
Создать внутреннюю тень
| 
 1 
2 
3 
4 
5 
 | 
 CGContextAddPath(context, path); 
CGContextSetLineWidth(context, 3.0f); 
CGContextSetStrokeColorWithColor(context, [UIColor colorWithRed:210.0f/255.0f green:210.0f/255.0f blue:210.0f/255.0f alpha:1.0f].CGColor); 
CGContextSetShadowWithColor(context, CGSizeMake(0.0f, 0.0f), 6.0f, [UIColor colorWithRed:0.0f/255.0f green:0.0f/255.0f blue:0.0f/255.0f alpha:1.0f].CGColor); 
CGContextDrawPath(context, kCGPathStroke); 
 | 
  Чтобы создать видимость UIBezierPath границы вокруг представления предупреждений, мы рисуем исходную UIBezierPath с тенью.  Путь будет по-прежнему обрезаться при первом вызове, чтобы обрезать контекст, в результате чего тень будет появляться только внутри штриховой линии.  Чтобы изменить размер внутренней тени, установите параметр размытия внутри CGContextSetShadowWidthColor на другое число. 
Перерисовать путь, чтобы избежать Pixilation
| 
 1 
2 
3 
4 
5 
6 
 | 
 CGContextRestoreGState(context); 
CGContextAddPath(context, path); 
CGContextSetLineWidth(context, 3.0f); 
CGContextSetStrokeColorWithColor(context, [UIColor colorWithRed:210.0f/255.0f green:210.0f/255.0f blue:210.0f/255.0f alpha:1.0f].CGColor); 
CGContextSetShadowWithColor(context, CGSizeMake(0.0f, 0.0f), 0.0f, [UIColor colorWithRed:0.0f/255.0f green:0.0f/255.0f blue:0.0f/255.0f alpha:0.1f].CGColor); 
CGContextDrawPath(context, kCGPathStroke); 
 | 
  Закругленные углы имеют тенденцию казаться пикселизированными после обрезки, поэтому наш последний фрагмент кода перерисовывает внешнюю строку, чтобы обеспечить ее четкость и чистоту.  Перед тем, как перерисовать внешнюю линию, мы вызываем CGContextRestoreGState() которая освобождает нашу первую область отсечения, поэтому мы можем рисовать поверх исходной линии. 
Шаг 4: протестируйте UIAlertView
  Запустите приложение на симуляторе или на своем устройстве, чтобы просмотреть UIAlertView и его пользовательскую графику. 

Вывод
  Создание графики с использованием Core Graphics — это тонкость и многоуровневость эффектов.  Существует множество графических элементов, которые можно настроить при настройке UIAlertView , и этот учебник охватывает только небольшую их часть.  Но дело в том, что все эти элементы можно настраивать и создавать программно, чтобы повысить удобство работы пользователя.