У меня есть фундаментальная проблема с использованием drawRect: Любой совет будет принят с благодарностью.
Приложению необходимо рисовать различные изображения .png в разное время, иногда с анимацией, иногда без.
Цель разработки, которой я надеялся придерживаться, - создать код внутри drawRect: очень простой и «тупой», т. Е. Просто рисовать и никакой другой логики приложения.
Для рисования изображения я использую drawAtPoint: метод UIImage. Поскольку этот метод не принимает CGContext в качестве параметра, он может быть вызван только внутри метода drawRect:. Итак, у меня есть:
- (void)drawRect:(CGRect)rect {
[firstImage drawAtPoint:CGPointMake(firstOffsetX, firstOffsetY)];
}
Все отлично и модно для одного изображения. Чтобы нарисовать несколько изображений (с течением времени), я выбрал поддержку массива словарей с каждым словарем, содержащим изображение, местоположение точки для рисования и флажок для включения / отключения рисования для этого изображения. Со временем я добавляю словари в массив и запускаю рисование с помощью метода setNeedsDisplay: UIView. Использование массива словарей позволяет мне полностью реконструировать весь дисплей в любое время. drawRect: теперь становится:
- (void)drawRect:(CGRect)rect {
for (NSMutableDictionary *imageDict in [self imageDisplayList]) {
if ([[imageDict objectForKey:@"needsDisplay"] boolValue]) {
[[imageDict objectForKey:@"image"] drawAtPoint:[[imageDict objectForKey:@"location"] CGPointValue]];
[imageDict setValue:[NSNumber numberWithBool:NO] forKey:@"needsDisplay"];
}
}
}
Все еще в порядке. Код прост и компактен. Анимация - вот где я сталкиваюсь с проблемами. Первая проблема заключается в том, где я могу разместить код анимации? Я помещаю это в UIView или UIViewController? Если в UIView, я должен положить его в drawRect: или в другом месте? Поскольку фактическая анимация зависит от общего состояния приложения, мне потребуются вложенные операторы switch, которые, если их поместить в drawRect:, будут выглядеть примерно так:
- (void)drawRect:(CGRect)rect {
for (NSMutableDictionary *imageDict in [self imageDisplayList]) {
if ([[imageDict objectForKey:@"needsDisplay"] boolValue]) {
switch ([self currentState]) {
case STATE_1:
switch ([[imageDict objectForKey:@"animationID"] intValue]) {
case ANIMATE_FADE_IN:
[self setAlpha:0.0];
[UIView beginAnimations:[[imageDict objectForKey:@"animationID"] intValue] context:nil];
[UIView setAnimationDelegate:self];
[UIView setAnimationCurve:UIViewAnimationCurveEaseIn];
[UIView setAnimationDuration:2];
[self setAlpha:1.0];
break;
case ANIMATE_FADE_OUT:
[self setAlpha:1.0];
[UIView beginAnimations:[[imageDict objectForKey:@"animationID"] intValue] context:nil];
[UIView setAnimationDelegate:self];
[UIView setAnimationCurve:UIViewAnimationCurveEaseOut];
[UIView setAnimationDuration:2];
[self setAlpha:0.0];
break;
case ANIMATE_OTHER:
// similar code here
break;
default:
break;
}
break;
case STATE_2:
// similar code here
break;
default:
break;
}
[[imageDict objectForKey:@"image"] drawAtPoint:[[imageDict objectForKey:@"location"] CGPointValue]];
[imageDict setValue:[NSNumber numberWithBool:NO] forKey:@"needsDisplay"];
}
}
[UIView commitAnimations];
}
Кроме того, для правильной работы нескольких последовательных анимаций необходим внешний управляющий механизм, включающий делегат анимации animationDidStop: callback, который бы устанавливал записи needsDisplay в словарях для разрешения / подавления рисования (и анимации).
Дело в том, что мы сейчас находимся в том, что все начинает выглядеть очень некрасиво. Более конкретно:
- drawRect: начинает быстро раздуваться и содержать код, который не просто рисует код
- UIView нуждается в неявной осведомленности о состоянии приложения
- общий процесс рисования теперь распределен по трем методам как минимум
И к сути этого поста: как я могу сделать это лучше? Что эксперты порекомендуют с точки зрения общей структуры? Как сохранить информацию о состоянии приложения вне поля зрения? Я смотрю на эту проблему с неправильной стороны. Есть ли какой-то совершенно другой подход, который я должен рассмотреть?