2017-08-31 179 views
2

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

enter image description here

+1

一个“高”视图与两个圆角矩形“切口”通过图层蒙版。 – DonMag

回答

2

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

  1. 创建UIView子命名GradientView管理梯度层。这很有帮助,因为这意味着您可以使用常规UIKit技术来管理渐变布局(自动布局约束,自动调整遮罩,UIKit动画)。

  2. 对于应该参与共同梯度,添加一个GradientView子视图的每个视图。同样设置每个GradientView的颜色,位置和起点和终点。

  3. 对于应该参与共同梯度,打开clipsToBounds每个视图。

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

通过这种方法,自动布局需要使梯度覆盖所有的意见,即使他们改变大小或走动的照顾。例如,当用户旋转设备时,您不必做任何特别的操作就可以使渐变效果更好。

因此,你的两个视图例如,我建议您设置视图层次是这样的:

unclipped

在上面的观点调试器的截图,我禁用裁剪。您可以看到两个渐变视图具有相同的渐变并共享相同的屏幕空间。该topGradienttopViewbottomGradient子视图是bottomView子视图。

如果我们把剪裁上,你只会看到里面topView适合的topGradient部分的界限,你只会看到里面bottomView适合的bottomGradient部分的界限。下面是它看起来像剪贴启用:

clipped

这是我的测试程序在模拟器的屏幕截图:

screen shot

这里的源代码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 

下面是我用来创建所有视图的代码:

- (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(或任何视图)的约束涵盖了一系列的观点:

- (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所需的最小空间。

+0

太棒了,男人! :) –

+0

请你能澄清这部分代码? +(Class)layerClass {return CAGradientLayer.class; }(CAGradientLayer *)gradientLayer {return(CAGradientLayer *)self.layer; }根据我的理解,你制作了基本图层CAGradientLayer,而不是通常的CALayer。并覆盖gradientLayer属性的getter。所以,它会返回CAGradientLayer而不是CALayer。我对吗? :) –

+0

你大多是正确的,但'gradientLayer' getter不会覆盖任何东西。 –

1

可以通过添加与该梯度的视图的顶视图,然后通过使掩模出UIBezierPath的,再加入这给视图上切出的形状做顶部(姑且称之为topView):

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