我如何添加跨越两个视图的渐变?
我知道该怎么做(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];
有几种方法可以做到这一点。 这里有一个方法:
-
创build一个名为
GradientView
的UIView
子类来pipe理渐变图层。 这很有帮助,因为这意味着您可以使用常规的UIKit技术来pipe理渐变布局(自动布局约束,自动调整遮罩,UIKitanimation)。 -
对于每个应该参与通用
GradientView
视图,添加一个GradientView
子视图。 设置每个GradientView
的颜色,位置和开始和结束点相同。 -
对于每个应该参与共同渐变的视图,请打开
clipsToBounds
。 -
使用自动布局约束使每个
GradientView
跨越所有参与的高级视图。 (了解约束可以跨越超视图/子视图边界是很重要的)。
采用这种方法,即使自动布局更改大小或移动,自动布局也可以使渐变覆盖所有视图。 例如,当用户旋转设备时,您不必做任何特别的操作就可以使渐变具有良好的animation效果。
因此,对于你的两个视图的例子,我build议你设置一个像这样的视图层次结构:
在上面的视图debugging器截图中,我禁用了裁剪。 您可以看到两个渐变视图具有相同的渐变并共享相同的屏幕空间。 topGradient
是topGradient
的子视图, bottomGradient
是bottomView
的子视图。
如果我们打开剪辑,只会看到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