We all know that the APP launches with a static image of LaunchImage. Many apps now start dynamically and skip in the upper right corner. Screenshot below:

Here is a way to do this kind of animation. The LaunchImage is still loaded, just a flash, and what I want to do is take the current LaunchImage image and manipulate it to give the illusion of changing the LaunchImage animation.

The idea is as follows: Customize the countdown progress bar according to UIBezierPath and CAShapeLayer, which is suitable for setting a countdown close startup page when the app starts. You can set progress bar color, fill color, progress bar width and click events.

Set skip button

ZLDrawCircleProgressBtn.h :

// Skip the button#import <UIKit/UIKit.h>

typedef void(^DrawCircleProgressBlock)(void);

@interface ZLDrawCircleProgressBtn : UIButton

//set track color
@property (nonatomic, strong) UIColor    *trackColor;

//set progress color
@property (nonatomic, strong) UIColor    *progressColor;

//set track background color
@property (nonatomic, strong) UIColor    *fillColor;

//set progress line width
@property (nonatomic, assign) CGFloat    lineWidth;

//setprogress duration @property (nonatomic, assign) CGFloat animationDuration; / * * *set complete callback
 *
 *  @param lineWidth line width
 *  @param block     block
 *  @param duration  time
 */
- (void)startAnimationDuration:(CGFloat)duration withBlock:(DrawCircleProgressBlock )block;

@end
Copy the code

ZLDrawCircleProgressBtn. M: initialize the skip button and progress

#import "ZLDrawCircleProgressBtn.h"

#define degreesToRadians(x) ((x) * M_PI / 180.0)@property (nonatomic, strong) CAShapeLayer *trackLayer; @property (nonatomic, strong) CAShapeLayer *progressLayer; @property (nonatomic, strong) UIBezierPath *bezierPath; @property (nonatomic, copy) DrawCircleProgressBlock myBlock; @end @implementation ZLDrawCircleProgressBtn - (instancetype)initWithFrame:(CGRect)frame {if (self == [super initWithFrame:frame]) {
        self.backgroundColor = [UIColor clearColor];
        
        [self.layer addSublayer:self.trackLayer];
        
    }
    return self;
}

- (UIBezierPath *)bezierPath {
    if(! _bezierPath) {CGFloat width = CGRectGetWidth(self.frame)/2.0f; CGFloat height = CGRectGetHeight (self. Frame) / 2.0 f; CGPoint centerPoint = CGPointMake(width, height);float radius = CGRectGetWidth(self.frame)/2;
        
        _bezierPath = [UIBezierPath bezierPathWithArcCenter:centerPoint
                                                     radius:radius
                                                 startAngle:degreesToRadians(-90)
                                                   endAngle:degreesToRadians(270)
                                                  clockwise:YES];
    }
    return _bezierPath;
}

- (CAShapeLayer *)trackLayer {
    if(! _trackLayer) { _trackLayer = [CAShapeLayer layer]; _trackLayer.frame = self.bounds; _tracklayer.fillcolor = self.fillcolor.cgcolor? self.fillColor.CGColor : [UIColor clearColor].CGColor ; _trackLayer.lineWidth = self.lineWidth ? self.lineWidth : 2.f; // Bottom circle color _tracklayer.strokecolor = self.trackcolor.cgcolor? Self.trackcolor.cgcolor: [UIColor colorWithRed:197/255.0 green:159/255.0 blue:82/255.0 alpha:0.3].cgcolor; _trackLayer.strokeStart = 0.f; _trackLayer.strokeEnd = 1.f; _trackLayer.path = self.bezierPath.CGPath; }return _trackLayer;
}

- (CAShapeLayer *)progressLayer {
    
    if(! _progressLayer) { _progressLayer = [CAShapeLayer layer]; _progressLayer.frame = self.bounds; _progressLayer.fillColor = [UIColor clearColor].CGColor; _progressLayer.lineWidth = self.lineWidth ? self.lineWidth : 2.f; _progressLayer.lineCap = kCALineCapRound; / / the progress bar circle. Color _progressLayer strokeColor = self. ProgressColor. CGColor? Self. ProgressColor. CGColor: [UIColor colorWithRed: 197/255.0 green: 159/255.0 blue: 82/255.0 alpha: 1) the CGColor; _progressLayer.strokeStart = 0.f; CABasicAnimation *pathAnimation = [CABasicAnimation animationWithKeyPath:@"strokeEnd"]; pathAnimation.duration = self.animationDuration; PathAnimation. FromValue = @ (0.0); PathAnimation. ToValue = @ (1.0); pathAnimation.removedOnCompletion = YES; pathAnimation.delegate = self; [_progressLayer addAnimation:pathAnimationforKey:nil];
        
        _progressLayer.path = _bezierPath.CGPath;
    }
    return _progressLayer;
}
Copy the code

Set up the proxy callback

#pragma mark -- CAAnimationDelegate
- (void)animationDidStop:(CAAnimation *)anim finished:(BOOL)flag {
    if(flag) { self.myBlock(); }}#pragma mark ---
- (void)startAnimationDuration:(CGFloat)duration withBlock:(DrawCircleProgressBlock )block {
    self.myBlock = block;
    self.animationDuration = duration;
    [self.layer addSublayer:self.progressLayer];
}
Copy the code

### c: start page zlStartPageView. h: display the bootpage method

/ / start page#import <UIKit/UIKit.h>

#define kscreenWidth [UIScreen mainScreen].bounds.size.width@interface ZLStartPageView: UIView /** * - (void)show; @endCopy the code

Zlstartpageview. m: 1. Initialize the start page

#import "ZLStartPageView.h"
#import "ZLDrawCircleProgressBtn.h"@property (nonatomic,strong) UIImageView *imageView; @property (nonatomic, strong) ZLDrawCircleProgressBtn *drawCircleBtn; Static int const showtime = 3; @implementation ZLStartPageView - (instancetype)initWithFrame:(CGRect)frame {if(self = [super initWithFrame:frame]) { // 1. Imageview = [[UIImageView alloc]initWithFrame:frame]; _imageView.contentMode = UIViewContentModeScaleAspectFill; _imageView.image = [UIImage imageNamed:@"LaunchImage_667h"]; [self addSubview:_imageView]; // skip the button ZLDrawCircleProgressBtn *drawCircleBtn = [[ZLDrawCircleProgressBtn alloc]initWithFrame:CGRectMake(kscreenWidth -55, 30, 40, 40)]; drawCircleBtn.lineWidth = 2; [drawCircleBtnsetTitle:@"Skip" forState:UIControlStateNormal];
        [drawCircleBtn setTitleColor:[UIColor  colorWithRed:197/255.0 green:159/255.0 blue:82/255.0 alpha:1] forState:UIControlStateNormal];
        drawCircleBtn.titleLabel.font = [UIFont systemFontOfSize:14];
        
        [drawCircleBtn addTarget:self action:@selector(removeProgress) forControlEvents:UIControlEventTouchUpInside];
        [self addSubview:drawCircleBtn];
        self.drawCircleBtn = drawCircleBtn;
        
    }
    return self;
}
Copy the code

2. Display the startup page and remove the callback when complete

- (void)show {// progress complete when the callback __weak __typeof(self) weakSelf = self; [weakSelf.drawCircleBtn startAnimationDuration:showtime withBlock:^{ [weakSelf removeProgress]; }]; UIWindow *window = [UIApplication sharedApplication].keyWindow; [window addSubview:self]; }Copy the code

3. Remove the startup page

/ / remove the start page - (void) removeProgress {self. ImageView. Transform = CGAffineTransformMakeScale (1, 1); self.imageView.alpha = 1; [UIView animateWithDuration: 0.3 animations: ^ {self. DrawCircleBtn. Hidden = NO; self. ImageView. Alpha = 0.05;  self.imageView.transform = CGAffineTransformMakeScale(5, 5);  } completion:^(BOOL finished) { self.drawCircleBtn.hidden = YES; [self.imageView removeFromSuperview]; }]; }Copy the code

The display code for the dynamic launch page is placed in AppDeleate.

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
    
    self.window = [[UIWindow alloc] initWithFrame:[UIScreen mainScreen].bounds];
    self.window.rootViewController = [[UINavigationController alloc] initWithRootViewController:[[HomeViewController alloc] init]];
    [self.window makeKeyAndVisible];
    
    [self setupStartPageView];
    
    returnYES; } /** * setupStartPageView {ZLStartPageView *startPageView = [[ZLStartPageView alloc] initWithFrame:self.window.bounds]; [startPageView show]; }Copy the code

This time can be tested, the effect is as follows:

If you want to start page loading ads, please go to ios-app to start page loading ads