我如何添加跨越两个视图的渐变?

我知道该怎么做(1)但我该怎么做(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]; 

在这里输入图像说明

有几种方法可以做到这一点。 这里有一个方法:

  1. 创build一个名为GradientViewUIView子类来pipe理渐变图层。 这很有帮助,因为这意味着您可以使用常规的UIKit技术来pipe理渐变布局(自动布局约束,自动调整遮罩,UIKitanimation)。

  2. 对于每个应该参与通用GradientView视图,添加一个GradientView子视图。 设置每个GradientView的颜色,位置和开始和结束点相同。

  3. 对于每个应该参与共同渐变的视图,请打开clipsToBounds

  4. 使用自动布局约束使每个GradientView跨越所有参与的高级视图。 (了解约束可以跨越超视图/子视图边界是很重要的)。

采用这种方法,即使自动布局更改大小或移动,自动布局也可以使渐变覆盖所有视图。 例如,当用户旋转设备时,您不必做任何特别的操作就可以使渐变具有良好的animation效果。

因此,对于你的两个视图的例子,我build议你设置一个像这样的视图层次结构:

正常曝光

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

如果我们打开剪辑,只会看到topGradient的一部分,它只能topGradient的边界内,而且只能看到bottomGradient的一部分,它可以放在bottomView的边界内。 下面是启用剪辑的外观:

修剪

这里是模拟器中我的testing程序的屏幕截图:

屏幕截图

以下是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 

以下是我用来创build所有视图的代码:

 - (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; } 

以下是我如何创build使GradientView (或任何视图)覆盖一组视图的约束:

 - (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]; } } 

coveree约束(默认情况下)具有所需的优先级,确保覆盖范围覆盖每个coveree的整个框架。 那么优先级较低的equal约束条件就可以确保满足者占据覆盖每个coveree的最小空间。

你可以通过在渐变的视图上添加一个视图,然后通过从UIBezierPath创build一个蒙UIBezierPath ,然后将其添加到顶部的视图(我们称之为UIBezierPath来切割形状:

  let yourPath: UIBezierPath = //create the desired bezier path for your shapes let mask = CAShapeLayer() mask.path = yourPath.cgPath topView.layer.mask = mask