2017-08-31 186 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