如何添加跨两个视图的渐变? [英] 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
的边界,而您只会看到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
覆盖每个coveree
的整个框架.优先级较低的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屋!