如何添加跨越两个视图的渐变? [英] How can I add a gradient that spans two views?

查看:25
本文介绍了如何添加跨越两个视图的渐变?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我知道怎么做 (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:

  1. 创建一个名为GradientViewUIView子类来管理渐变层.这很有用,因为这意味着您可以使用普通的 UIKit 技术来管理渐变布局(自动布局约束、自动调整蒙版、UIKit 动画).

  1. Create a UIView subclass named GradientView 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:

在上面的视图调试器屏幕截图中,我禁用了剪辑.您可以看到两个渐变视图具有相同的渐变并共享相同的屏幕空间.topGradienttopView 的子视图,bottomGradientbottomView 的子视图.

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屋!

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