CAGradientLayer,不能很好地调整大小,旋转时撕裂 [英] CAGradientLayer, not resizing nicely, tearing on rotation

查看:16
本文介绍了CAGradientLayer,不能很好地调整大小,旋转时撕裂的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在尝试获取我用来创建漂亮渐变背景的 CAGradientLayers,以便在旋转和模态视图演示中很好地调整大小,但它们不会打球.

这是我刚刚创建的一个视频,展示了我的问题:注意旋转时的撕裂.

另请注意,此视频是通过在 OS X 上拍摄 iPhone 模拟器而创建的.我已减慢视频中的动画速度以突出我的问题.

幸运的是,这是一个很容易解决的问题.你需要让你的渐变层由一个视图管理.您可以通过创建一个使用 CAGradientLayer 作为其层的 UIView 子类来实现.代码很小:

//GradientView.h@interface GradientView : UIView@property (nonatomic, strong, readonly) CAGradientLayer *layer;@结尾//渐变视图.m@implementation 渐变视图@动态层;+ (Class)layerClass {返回 [CAGradientLayer 类];}@结尾

然后您需要更改代码以使用 GradientView 而不是 CAGradientLayer.由于您现在使用的是视图而不是图层,因此您可以设置自动调整大小蒙版以将渐变大小保持为其超视图,因此您以后无需执行任何操作来处理旋转:

@interface ViewController()@property (nonatomic, strong) GradientView *gradientView;@结尾@实现视图控制器- (void)viewDidLoad {[超级viewDidLoad];self.gradientView = [[GradientView alloc] initWithFrame:self.view.bounds];self.gradientView.autoresizingMask = UIViewAutoresizingFlexibleWidth |UIViewAutoresizingFlexibleHeight;self.gradientView.layer.colors = @[ (__bridge id)[UIColor blueColor].CGColor, (__bridge id)[UIColor blackColor].CGColor];[self.view addSubview:self.gradientView];}@结尾

结果如下:

I'm trying to get my CAGradientLayers, that i'm using to create nice gradient backgrounds, to resize nicely on rotation and modal view presentation, but they will not play ball.

Here is a video I just created showing my problem: Notice the tearing on rotation.

Also please note this video was created by filming the iPhone Simulator on OS X. I have slowed down the animations in the video to highlight my issue.

Video of Problem...

Here is an Xcode project which I just created (which is the source for the app shown in the video), basically as illustrated the issue occurs on rotation and especially when views are presented modally:

Xcode Project, modally presenting views with CAGradientLayer backgrounds...

For what it's worth I understand that using:

    [[self view] setBackgroundColor:[UIColor blackColor]];

does a reasonable job of making the transitions a bit more seamless and less jarring, but if you look at the video when I, whilst currently in landscape mode, modally present a view, you will see why the above code will not help.

Any ideas what I can do to sort this out?

John

解决方案

When you create a layer (like your gradient layer), there's no view managing the layer (even when you add it as a sublayer of some view's layer). A standalone layer like this doesn't participate in the UIView animation system.

So when you update the frame of the gradient layer, the layer animates the change with its own default animation parameters. (This is called "implicit animation".) These default parameters don't match the animation parameters used for interface rotation, so you get a weird result.

I didn't look at your project but it's trivial to reproduce your problem with this code:

@interface ViewController ()

@property (nonatomic, strong) CAGradientLayer *gradientLayer;

@end

@implementation ViewController

- (void)viewDidLoad {
    [super viewDidLoad];

    self.gradientLayer = [CAGradientLayer layer];
    self.gradientLayer.colors = @[ (__bridge id)[UIColor blueColor].CGColor, (__bridge id)[UIColor blackColor].CGColor ];
    [self.view.layer addSublayer:self.gradientLayer];
}

- (void)viewDidLayoutSubviews {
    [super viewDidLayoutSubviews];
    self.gradientLayer.frame = self.view.bounds;
}

@end

Here's what that looks like, with slow motion enabled in the simulator:

Fortunately, this is an easy problem to fix. You need to make your gradient layer be managed by a view. You do that by creating a UIView subclass that uses a CAGradientLayer as its layer. The code is tiny:

// GradientView.h

@interface GradientView : UIView

@property (nonatomic, strong, readonly) CAGradientLayer *layer;

@end

// GradientView.m

@implementation GradientView

@dynamic layer;

+ (Class)layerClass {
    return [CAGradientLayer class];
}

@end

Then you need to change your code to use GradientView instead of CAGradientLayer. Since you're using a view now instead of a layer, you can set the autoresizing mask to keep the gradient sized to its superview, so you don't have to do anything later to handle rotation:

@interface ViewController ()

@property (nonatomic, strong) GradientView *gradientView;

@end

@implementation ViewController

- (void)viewDidLoad {
    [super viewDidLoad];

    self.gradientView = [[GradientView alloc] initWithFrame:self.view.bounds];
    self.gradientView.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight;
    self.gradientView.layer.colors = @[ (__bridge id)[UIColor blueColor].CGColor, (__bridge id)[UIColor blackColor].CGColor ];
    [self.view addSubview:self.gradientView];
}

@end

Here's the result:

这篇关于CAGradientLayer,不能很好地调整大小,旋转时撕裂的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆