不规则形状的Mask动画
效果
源码
https://github.com/YouXianMing/Animations
// // MaskShapeViewController.m // Animations // // Created by YouXianMing on 16/7/10. // Copyright © 2016年 YouXianMing. All rights reserved. // #import "MaskShapeViewController.h" #import "AppleSystemService.h" #import "JSAnimatedImagesView.h" #import "CutOutClearView.h" #import "UIView+SetRect.h" #import "UIFont+Fonts.h" #import "FBShimmeringView.h" typedef enum : NSUInteger { kUpJsView = 1000, kDownJsView, } EMaskShapeViewControllerValue; @interface MaskShapeViewController () <JSAnimatedImagesViewDataSource> @property (nonatomic, strong) JSAnimatedImagesView *upJsView; @property (nonatomic, strong) NSArray *upDataSource; @property (nonatomic, strong) JSAnimatedImagesView *downJsView; @property (nonatomic, strong) NSArray *downDataSource; @end @implementation MaskShapeViewController - (void)setup { [super setup]; self.backgroundView.backgroundColor = [UIColor blackColor]; CGFloat gap = 4.f; CGFloat offset = 50.f; { CutOutClearView *areaView = [[CutOutClearView alloc] initWithFrame:CGRectMake(0, 0, Width, self.contentView.height / 2.f + offset - gap)]; areaView.fillColor = [UIColor clearColor]; areaView.areaColor = [UIColor blackColor]; UIBezierPath *path = [UIBezierPath bezierPath]; [path moveToPoint:CGPointMake(gap, gap)]; [path addLineToPoint:CGPointMake(Width - gap, gap)]; [path addLineToPoint:CGPointMake(Width - gap, areaView.height)]; [path addLineToPoint:CGPointMake(gap, areaView.height - (offset - gap) * 2 - gap)]; [path closePath]; areaView.paths = @[path]; self.upDataSource = @[[UIImage imageNamed:@"1"], [UIImage imageNamed:@"2"], [UIImage imageNamed:@"3"], [UIImage imageNamed:@"4"], [UIImage imageNamed:@"5"]]; self.upJsView = [[JSAnimatedImagesView alloc] initWithFrame:CGRectMake(0, 0, Width, self.contentView.height / 2.f + offset - gap)]; self.upJsView.transitionDuration = 2.f; self.upJsView.tag = kUpJsView; self.upJsView.dataSource = self; self.upJsView.layer.masksToBounds = YES; self.upJsView.maskView = areaView; [self.contentView addSubview:self.upJsView]; } { CutOutClearView *areaView = [[CutOutClearView alloc] initWithFrame:CGRectMake(0, 0, Width, self.contentView.height / 2.f + (offset - gap))]; areaView.fillColor = [UIColor clearColor]; areaView.areaColor = [UIColor blackColor]; UIBezierPath *path = [UIBezierPath bezierPath]; [path moveToPoint:CGPointMake(gap, 0)]; [path addLineToPoint:CGPointMake(gap, areaView.height - gap)]; [path addLineToPoint:CGPointMake(Width - gap, areaView.height - gap)]; [path addLineToPoint:CGPointMake(Width - gap, (offset - gap) * 2 + gap)]; [path closePath]; areaView.paths = @[path]; self.downDataSource = @[[UIImage imageNamed:@"pic_1"], [UIImage imageNamed:@"pic_2"], [UIImage imageNamed:@"pic_3"], [UIImage imageNamed:@"pic_4"]]; self.downJsView = [[JSAnimatedImagesView alloc] initWithFrame:CGRectMake(0, 0, Width, self.contentView.height / 2.f + offset - gap)]; self.downJsView.transitionDuration = 2.f; self.downJsView.tag = kDownJsView; self.downJsView.dataSource = self; self.downJsView.layer.masksToBounds = YES; self.downJsView.maskView = areaView; self.downJsView.bottom = self.contentView.height; [self.contentView addSubview:self.downJsView]; } } #pragma mark - JSAnimatedImagesViewDataSource - (NSUInteger)animatedImagesNumberOfImages:(JSAnimatedImagesView *)animatedImagesView { NSUInteger count = 0; animatedImagesView.tag == kUpJsView ? (count = self.upDataSource.count) : (count = self.downDataSource.count); return count; } - (UIImage *)animatedImagesView:(JSAnimatedImagesView *)animatedImagesView imageAtIndex:(NSUInteger)index { UIImage *image = nil; animatedImagesView.tag == kUpJsView ? (image = self.upDataSource[index]) : (image = self.downDataSource[index]); return image; } #pragma mark - Overwrite methods. - (void)buildTitleView { [super buildTitleView]; // Title label. UILabel *headlinelabel = [UILabel new]; headlinelabel.font = [UIFont HeitiSCWithFontSize:20.f]; headlinelabel.textAlignment = NSTextAlignmentCenter; headlinelabel.textColor = [UIColor cyanColor]; headlinelabel.text = self.title; [headlinelabel sizeToFit]; headlinelabel.center = self.titleView.middlePoint; FBShimmeringView *shimmeringView = [[FBShimmeringView alloc] initWithFrame:self.titleView.bounds]; shimmeringView.shimmering = YES; shimmeringView.shimmeringBeginFadeDuration = 0.3; shimmeringView.shimmeringOpacity = 0.1f; shimmeringView.shimmeringAnimationOpacity = 1.f; [self.titleView addSubview:shimmeringView]; shimmeringView.contentView = headlinelabel; // Line. UIView *line = [[UIView alloc] initWithFrame:CGRectMake(0, 63.5, self.view.width, 0.5f)]; line.backgroundColor = [[UIColor grayColor] colorWithAlphaComponent:0.25f]; [self.titleView addSubview:line]; [self.titleView addSubview:headlinelabel]; // Back button. UIImage *image = [UIImage imageNamed:@"backIconVer2"]; UIButton *backButton = [[UIButton alloc] initWithFrame:CGRectMake(0, 0, 100, 64)]; backButton.center = CGPointMake(20, self.titleView.middleY); [backButton setImage:image forState:UIControlStateNormal]; [backButton addTarget:self action:@selector(popSelf) forControlEvents:UIControlEventTouchUpInside]; [backButton.imageView setContentMode:UIViewContentModeCenter]; [self.titleView addSubview:backButton]; } - (void)popSelf { [self popViewControllerAnimated:YES]; } @end
细节
// // CutOutClearView.h // Animations // // Created by YouXianMing on 16/7/10. // Copyright © 2016年 YouXianMing. All rights reserved. // #import <UIKit/UIKit.h> @interface CutOutClearView : UIView /** * The total fill color, you can used it as the view's background color. */ @property (nonatomic, strong) UIColor *fillColor; /** * The paths area color. */ @property (nonatomic, strong) UIColor *areaColor; /** * Path array. */ @property (nonatomic, strong) NSArray <UIBezierPath *> *paths; @end
// // CutOutClearView.m // Animations // // Created by YouXianMing on 16/7/10. // Copyright © 2016年 YouXianMing. All rights reserved. // #import "CutOutClearView.h" @implementation CutOutClearView - (instancetype)initWithFrame:(CGRect)frame { if (self = [super initWithFrame:frame]) { self.fillColor = [UIColor whiteColor]; self.backgroundColor = [UIColor clearColor]; self.opaque = NO; } return self; } - (void)drawRect:(CGRect)rect { [super drawRect:rect]; [self.fillColor setFill]; UIRectFill(rect); CGContextRef context = UIGraphicsGetCurrentContext(); if (self.areaColor && self.paths.count) { UIBezierPath *path = nil; for (int i = 0; i < self.paths.count; i++) { i == 0 ? path = self.paths[i] : [path appendPath:self.paths[i]]; } CGFloat red = 0; CGFloat green = 0; CGFloat blue = 0; CGFloat alpha = 0; [self.areaColor getRed:&red green:&green blue:&blue alpha:&alpha]; CGContextAddPath(context, path.CGPath); CGContextSetRGBFillColor(context, red, green, blue, alpha); CGContextFillPath(context); } else { for (UIBezierPath *path in self.paths) { CGContextAddPath(context, path.CGPath); CGContextSetBlendMode(context, kCGBlendModeClear); CGContextFillPath(context); } } } @end