如何添加跨越两个视图的渐变? [英] How can I add a gradient that spans two views?
问题描述
我知道怎么做 (1) 但我该怎么做 (2)?
I know how to do (1) but how can I do (2)?
UIView *view = [[UIView alloc] initWithFrame:CGRectMake(0, 0, 320, 50)];
CAGradientLayer *gradient = [CAGradientLayer layer];
gradient.frame = view.bounds;
gradient.colors = @[(id)[UIColor blueColor].CGColor, (id)[UIColor redColor].CGColor];
[view.layer insertSublayer:gradient atIndex:0];
推荐答案
有几种方法可以做到这一点.这是一种方法:
There are several ways you could do this. Here's one way:
创建一个名为
GradientView
的UIView
子类来管理渐变层.这很有用,因为这意味着您可以使用普通的 UIKit 技术来管理渐变布局(自动布局约束、自动调整蒙版、UIKit 动画).
Create a
UIView
subclass namedGradientView
to manage the gradient layer. This is helpful because it means you can use the normal UIKit techniques to manage the gradient layout (auto layout constraints, autoresizing masks, UIKit animations).
对于应该参与公共渐变的每个视图,添加一个 GradientView
子视图.将每个 GradientView
的颜色、位置以及起点和终点设置为相同.
For each view that should participate in the common gradient, add a GradientView
subview. Set up each GradientView
's colors, locations, and start and end points identically.
对于应该参与公共渐变的每个视图,打开clipsToBounds
.
For each view that should participate in the common gradient, turn on clipsToBounds
.
使用自动布局约束使每个 GradientView
跨越所有参与的超级视图.(重要的是要了解约束可以跨越父视图/子视图边界).
Use auto layout constraints to make each GradientView
span all of the participating superviews. (It's important to understand that constraints can cross superview/subview boundaries).
使用这种方法,自动布局负责使渐变覆盖所有视图,即使它们改变大小或移动.例如,当用户旋转设备时,您无需执行任何特殊操作即可使渐变动画效果良好.
With this approach, auto layout takes care of making the gradient cover all of the views even if they change size or move around. For example, you won't have to do anything special to make the gradients animate nicely when the user rotates the device.
因此,对于您的双视图示例,我建议您设置这样的视图层次结构:
Thus, for your two-view example, I'm proposing that you set up a view hierarchy like this:
在上面的视图调试器屏幕截图中,我禁用了剪辑.您可以看到两个渐变视图具有相同的渐变并共享相同的屏幕空间.topGradient
是 topView
的子视图,bottomGradient
是 bottomView
的子视图.
In the view debugger screenshot above, I disabled clipping. You can see that the two gradient views have identical gradients and share the same screen space. The topGradient
is a subview of topView
and bottomGradient
is a subview of bottomView
.
如果我们打开裁剪,您将只会看到 topGradient
适合topView
边界的部分,而您只会看到 topGradient
的部分code>bottomGradient 适合 bottomView
的边界.这是启用剪辑后的样子:
If we turn clipping on, you'll only see the part of topGradient
that fits inside topView
's bounds, and you'll only see the part of bottomGradient
that fits inside bottomView
's bounds. Here's what it looks like with clipping enabled:
这是我在模拟器中的测试程序的屏幕截图:
And here's a screen shot of my test program in the simulator:
这是GradientView
的源代码:
@interface GradientView: UIView
@property (nonatomic, strong, readonly) CAGradientLayer *gradientLayer;
@end
@implementation GradientView
+ (Class)layerClass { return CAGradientLayer.class; }
- (CAGradientLayer *)gradientLayer { return (CAGradientLayer *)self.layer; }
@end
这是我用来创建所有视图的代码:
Here's the code I used to create all of the views:
- (void)viewDidLoad {
[super viewDidLoad];
UIView *topView = [[UIView alloc] initWithFrame:CGRectMake(20, 20, 100, 50)];
topView.layer.cornerRadius = 10;
topView.clipsToBounds = YES;
UIView *topGradient = [self newGradientView];
[topView addSubview:topGradient];
[self.view addSubview:topView];
UIView *bottomView = [[UIView alloc] initWithFrame:CGRectMake(20, 90, 100, 50)];
bottomView.layer.cornerRadius = 10;
bottomView.clipsToBounds = YES;
UIView *bottomGradient = [self newGradientView];
[bottomView addSubview:bottomGradient];
[self.view addSubview:bottomView];
[self constrainView:topGradient toCoverViews:@[topView, bottomView]];
[self constrainView:bottomGradient toCoverViews:@[topView, bottomView]];
}
- (GradientView *)newGradientView {
GradientView *gv = [[GradientView alloc] initWithFrame:CGRectZero];
gv.translatesAutoresizingMaskIntoConstraints = NO;
gv.gradientLayer.colors = @[(__bridge id)UIColor.blueColor.CGColor, (__bridge id)UIColor.redColor.CGColor];
return gv;
}
这里是我如何创建约束使 GradientView
(或任何视图)覆盖一组视图:
And here's how I create the constraints that make a GradientView
(or any view) cover a set of views:
- (void)constrainView:(UIView *)coverer toCoverViews:(NSArray<UIView *> *)coverees {
for (UIView *coveree in coverees) {
NSArray<NSLayoutConstraint *> *cs;
cs = @[
[coverer.leftAnchor constraintLessThanOrEqualToAnchor:coveree.leftAnchor],
[coverer.rightAnchor constraintGreaterThanOrEqualToAnchor:coveree.rightAnchor],
[coverer.topAnchor constraintLessThanOrEqualToAnchor:coveree.topAnchor],
[coverer.bottomAnchor constraintGreaterThanOrEqualToAnchor:coveree.bottomAnchor]];
[NSLayoutConstraint activateConstraints:cs];
cs = @[
[coverer.leftAnchor constraintEqualToAnchor:coveree.leftAnchor],
[coverer.rightAnchor constraintEqualToAnchor:coveree.rightAnchor],
[coverer.topAnchor constraintEqualToAnchor:coveree.topAnchor],
[coverer.bottomAnchor constraintEqualToAnchor:coveree.bottomAnchor]];
for (NSLayoutConstraint *c in cs) { c.priority = UILayoutPriorityDefaultHigh; }
[NSLayoutConstraint activateConstraints:cs];
}
}
greaterThanOrEqual
/lessThanOrEqual
约束(默认情况下)具有必需的优先级,确保coverer
覆盖每个承保人
.equal
约束,具有较低的优先级,然后确保coverer
占据覆盖每个coveree
所需的最小空间.
The greaterThanOrEqual
/lessThanOrEqual
constraints, which (by default) have required priority, ensure that coverer
covers the entire frame of each coveree
. The equal
constraints, which have lower priority, then ensure that coverer
occupies the minimum space required to cover each coveree
.
这篇关于如何添加跨越两个视图的渐变?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!