在 iOS 上,如果一个视图有多个层,drawRect 可以只选择一个层来显示吗?
Posted
技术标签:
【中文标题】在 iOS 上,如果一个视图有多个层,drawRect 可以只选择一个层来显示吗?【英文标题】:On iOS, if a view has several layers, can drawRect just choose a layer to display? 【发布时间】:2012-05-27 06:49:08 【问题描述】:在ios上,如果一个view有好几层,那么drawRect
方法是否可以选择任意一层显示,1秒后再选择另一层显示,实现动画效果?
现在,我有几个图层,但我不认为它们是视图的图层(它们只是单独的图层,不是父图层的子图层),因为我只是使用它们创建的
CGLayerCreateWithContext(context, self.view.bounds.size, NULL);
在drawRect
,我使用
CGContextDrawLayerAtPoint(context, self.bounds.origin, layer1);
将图层绘制到视图上...它可以工作,但这不就像将图层绘制到图层上(将图层绘制到视图的图层上)吗?难道没有更快的方法,就是告诉视图使用layer1
或layer2
,有点像
self.layer = layer1;
但它不能,因为layer
是只读的。这可以实现吗?
【问题讨论】:
您是否试图通过将每一帧放在单独的图层中并交换图层来实现动画? 这个问题没有多大意义,因为你混淆了两个不同的东西:CGLayer
s 和CALayer
s。它们具有相似的名称,但它们完全不同。你不能混合和匹配它们。 CGLayerCreateWithContext
是 CGLayer
,但 self.layer
是 CALayer
。
@PartiallyFinite 是的...例如 2 层,并使用这 2 层制作动画...
@Kurt我读到,与其画到BitmapContext中,不如画到一个Layer中,因为它缓存在显卡中,所以这个Layer是CGLayer?是否也可以绘制到 CALayer 中? (嗯......然后我看到了PartiallyFinite的回答......几乎画到一个视图中,然后从视图中提取图层......)
@PartiallyFinite 答案的重要部分不是他“从视图中提取图层”的部分——这只是让图层向您展示的一种简单方法。在实践中,您可以轻松创建 CALayer
并设置其 backgroundColor
属性。
【参考方案1】:
您正在尝试使用CGLayer
绘图方法绘制CALayer
对象。这些是不同的东西,不能互换使用。但是,如果我正确理解了您的问题,那么您完全不需要在一段时间后使用drawRect:
在图层之间切换。这是我的基本工作代码示例:
#import <QuartzCore/QuartzCore.h>
@interface TTView
NSUInteger index;
NSArray *layers;
CALayer *currentLayer;
@end
@implementation TTView
- (void)switchView
// Remove the currently visible layer
[currentLayer removeFromSuperlayer];
// Add in the next layer
currentLayer = [layers objectAtIndex:index];
[self.layer addSublayer:currentLayer];
// Increment the index for next time
index += 1;
if (index > [layers count] - 1)
// If we have reached the end of the array, go back to the start. You can exit the loop here by calling a different method followed by return;
index = 0;
// Call this method again after 1 second
[self performSelector:@selector(switchView) withObject:nil afterDelay:1];
- (id)initWithCoder:(NSCoder *)aDecoder
// Basic initialisation. Move this to whatever method your view inits with.
self = [super initWithCoder:aDecoder];
if (self)
// Create some random objects with layers to display. Place your layers into the array here.
UIView *a = [[UIView alloc] initWithFrame:self.bounds];
a.backgroundColor = [UIColor redColor];
UIView *b = [[UIView alloc] initWithFrame:self.bounds];
b.backgroundColor = [UIColor greenColor];
UIView *c = [[UIView alloc] initWithFrame:self.bounds];
c.backgroundColor = [UIColor blueColor];
// Add the layers to the array.
layers = [[NSArray alloc] initWithObjects:a.layer, b.layer, c.layer, nil];
// Call the method to start the loop.
[self switchView];
return self;
显然,您应该用您计划以这种方式制作动画的任何图层替换我的 3 个纯色视图,并可能整理实例变量。这只是一个基本的代码示例,可以满足您的需求。
【讨论】:
所以如果第一层要在里面画一个矩形,第二层需要在里面画一个圆,那该怎么做呢?我尝试使用FooView
而不是UIView
... 并在FooView
中使用drawRect
来绘制它...但是该层完全是黑色...(但如果我再想一想...@ 987654329@ 由 keyWindow
(顶视图)和向下的视图层次结构的运行循环调用...在上面的代码示例中,没有为这些视图调用 drawRect
的这种概念。)
【参考方案2】:
按照@PartiallyFinite 的示例,通过将视图层的contents
属性设置为您选择的CGImage
,这是获得相同效果的类似方法。
这比覆盖-drawRect:
并在那里绘制更有效,因为它避免了额外的绘制操作并上传到视频硬件。
#import <QuartzCore/QuartzCore.h>
@interface TTView
NSUInteger index;
NSMutableArray *images;
@end
@implementation TTView
- (id)initWithCoder:(NSCoder *)aDecoder
// Basic initialisation. Move this to whatever method your view inits with.
self = [super initWithCoder:aDecoder];
if (self)
// Create some random images to display. Place your images into the array here.
CGSize imageSize = self.bounds.size;
images = [[NSMutableArray alloc] init];
[images addObject:[self imageWithSize:imageSize color:[UIColor redColor]]];
[images addObject:[self imageWithSize:imageSize color:[UIColor greenColor]]];
[images addObject:[self imageWithSize:imageSize color:[UIColor blueColor]]];
[self switchView];
return self;
- (UIImage*)imageWithSize:(CGSize)imageSize color:(UIColor*)color
UIGraphicsBeginImageContext(imageSize);
// Draw whatever you like here.
// As an example, we just fill the whole image with the color.
[color set];
UIRectFill(CGRectMake(0, 0, imageSize.width, imageSize.height));
UIImage* image = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
return image;
- (void)switchView
UIImage* image = [images objectAtIndex:index];
self.layer.contents = (id)(image.CGImage);
index = (index + 1) % images.count;
[self performSelector:@selector(switchView) withObject:nil afterDelay:1];
// DO NOT override -drawRect:, and DO NOT call -setNeedsDisplay.
// You're already providing the view's contents.
@end
【讨论】:
hm...self.layer.contents = [images objectAtIndex:index].CGImage;
现在会说 CGImage
is a property not found... 我尝试将第一部分转换为 (UIImage*)
但仍然错误
如果它是self.layer.contents = (id) ((UIImage*)[images objectAtIndex:index]).CGImage;
,则该行可以工作
是的,抱歉,我错过了将演员表添加到 (id)
那里。固定。以上是关于在 iOS 上,如果一个视图有多个层,drawRect 可以只选择一个层来显示吗?的主要内容,如果未能解决你的问题,请参考以下文章
使用 splitViewController 在 iPad 故事板上出现黑屏
在 iOS 7 上,在 viewDidLoad 中设置图层变换会破坏自动布局