我在使用 drawRect 时遇到了一个基本问题:任何建议将不胜感激。
应用程序需要在不同的时间绘制各种 .png 图像,有时有动画,有时没有。
我希望坚持的一个设计目标是在 drawRect 中包含代码:非常简单且“愚蠢” - 即只进行绘图而没有其他应用程序逻辑。
要绘制图像,我使用 UIImage 的 drawAtPoint: 方法。由于该方法不以 CGContext 作为参数,因此只能在 drawRect: 方法中调用。所以我有:
- (void)drawRect:(CGRect)rect {
[firstImage drawAtPoint:CGPointMake(firstOffsetX, firstOffsetY)];
}
一张照片的一切都很好。为了绘制多个图像(随着时间的推移),我采用的方法是维护一个字典数组,每个字典包含一个图像、要绘制的点位置和一个启用/抑制该图像绘制的标志。随着时间的推移,我将字典添加到数组中,并通过 UIView 的 setNeedsDisplay: 方法触发绘图。使用字典数组可以让我随时完全重建整个显示。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: 回调的外部控制机制,它将设置字典中的 needsDisplay 条目以允许/禁止绘制(和动画)。
我们现在的重点是,这一切都开始变得非常丑陋。进一步来说:
- drawRect:开始迅速膨胀并包含不是“只是绘制”代码的代码
- UIView 需要对应用程序状态的隐式感知
- 整个绘图过程现在至少分布在三种方法中
以及这篇文章的重点:我怎样才能做得更好?就整体结构而言,专家们会推荐什么?如何将应用程序状态信息保持在视图之外?我是不是从错误的方向看这个问题。我应该考虑一些完全不同的方法吗?