ios学习开源代码系列(一)LHLoadingView

来源:互联网 发布:车牌识别有没有数据库 编辑:程序博客网 时间:2024/06/04 01:25

模仿是学习的必经阶段,所以接下来决定学习开源的代码,来发现自己的不足,学习别人的优点

第一个学习的框架是LHLoadingView开源代码

首先看看项目的代码结构


项目结构很简单,主要包活

1.自定义的view,view里面实现了动画效果

2.view的controller


首先看看controller,里面主要做的使view定时执行动画,代码就只有几行,不复杂



然后我们看看自定义的view,view只有一个 show 方法

@interface LeoLoadingView : UIView-(void)showView:(BOOL)show;@end

下面贴上实现代码

#import "LeoLoadingView.h"#define AnimationTime   0.3#define kDotSize                (CGSizeMake(0.4 * self.frame.size.width, 0.4 * self.frame.size.height))#define LeftTopPosition         (CGPointMake(0, 0))#define LeftTBottomPosition     (CGPointMake(0, 0.6 * self.frame.size.height))#define RightBottomPosition     (CGPointMake(0.6 * self.frame.size.width, 0.6 * self.frame.size.height))#define RightTopPosition        (CGPointMake(0.6 * self.frame.size.width, 0))#define kDotColor               [UIColor colorWithRed:200/255.0 green:206/255.0 blue:221/255.0 alpha:1.0]@interface LeoLoadingView()@property (strong, nonatomic) UIView *dotView0,*dotView1,*dotView2;@property (strong, nonatomic) NSArray *dotViews;@property (assign, nonatomic) NSInteger dotIndex;@property (strong, nonatomic) NSTimer *timer;@end@implementation LeoLoadingView- (id)initWithFrame:(CGRect)frame{    self = [super initWithFrame:frame];    if (self) {        // Initialization code        self.hidden = YES;    }    return self;}- (void)layoutSubviews{    [super layoutSubviews];    [self initView];}- (void)initView{    self.backgroundColor = [UIColor clearColor];//    self.clipsToBounds = YES;    self.userInteractionEnabled = NO;        _dotView0 = [[UIView alloc]initWithFrame:(CGRect){RightBottomPosition, kDotSize}];    _dotView0.backgroundColor = kDotColor;    [self addSubview:_dotView0];        _dotView1 = [[UIView alloc]initWithFrame:(CGRect){LeftTBottomPosition, kDotSize}];    _dotView1.backgroundColor = kDotColor;    [self addSubview:_dotView1];        _dotView2 = [[UIView alloc]initWithFrame:(CGRect){LeftTopPosition, kDotSize}];    _dotView2.backgroundColor = kDotColor;    [self addSubview:_dotView2];        _dotViews = @[_dotView0, _dotView1, _dotView2];    _dotIndex = 0;}-(void)showView:(BOOL)show{    if (show) {        self.hidden = NO;        if (!_timer) {            _timer = [NSTimer timerWithTimeInterval:AnimationTime target:self selector:@selector(beginAnimation) userInfo:nil repeats:YES];            [[NSRunLoop mainRunLoop]addTimer:_timer forMode:NSRunLoopCommonModes];        }    }    else{        [_timer invalidate];        _timer = nil;        self.hidden = YES;    }}-(void)beginAnimation{    [UIView animateWithDuration:AnimationTime delay:0 options:UIViewAnimationOptionCurveLinear animations:^{        UIView *dotView = _dotViews[_dotIndex];        [self moveDotViewToNextPosition:dotView];                _dotIndex ++;        _dotIndex = _dotIndex > 2 ? 0 : _dotIndex;            } completion:nil];}-(void)moveDotViewToNextPosition:(UIView*)dotView{    if (CGPointEqualToPoint(dotView.frame.origin, LeftTopPosition)) {        dotView.frame = (CGRect){LeftTBottomPosition, dotView.frame.size};    }    else if (CGPointEqualToPoint(dotView.frame.origin, LeftTBottomPosition)) {        dotView.frame = (CGRect){RightBottomPosition, dotView.frame.size};    }    else if (CGPointEqualToPoint(dotView.frame.origin, RightBottomPosition)) {        dotView.frame = (CGRect){RightTopPosition, dotView.frame.size};    }    else if (CGPointEqualToPoint(dotView.frame.origin, RightTopPosition)) {        dotView.frame = (CGRect){LeftTopPosition, dotView.frame.size};    }}@end


那么多个方法,我们首先要关注的,也是很重要的一个方法就是

- (void)layoutSubviews{    [super layoutSubviews];    [self initView];}

当自定义view首次加载到父view中时(或者当view是rootview时,屏幕发生旋转;或者view的frame发生改变;又或往view添加subview时),会调用这个方法,通过initView来初始化自定义view。这里有一个有趣的问题,大家猜猜当这个工程启动的时候,layoutSubviews会被调用多少次?通过打断点,我们可以发现是两次。为什么呢?那是因为我们在storyboard里面添加了两个自定义的view,既然有两个view,那么当这两个view添加进父view的时候,自然就会调用两次了~


第二个要关注的方法是

-(void)showView:(BOOL)show{    if (show) {        self.hidden = NO;        if (!_timer) {            _timer = [NSTimer timerWithTimeInterval:AnimationTime target:self selector:@selector(beginAnimation) userInfo:nil repeats:YES];            [[NSRunLoop mainRunLoop]addTimer:_timer forMode:NSRunLoopCommonModes];        }    }    else{        [_timer invalidate];        _timer = nil;        self.hidden = YES;    }}

NSRunLoop是平时比较少接触的概念,下面说说自己查阅资料后的理解

NSRunLoop和线程是分不开的,ios里面每一个线程(包活自己新建的和应用的mian线程)都有一个NSRunLoop对象

一般来说,一个线程当执行一段代码后,就会退出,那如果我想在线程里面循环执行某项任务,那怎么办呢,我们可能会这样写

void threadMethod(){    while(true)    {        do some job...        sleep(一段时间)    }}

而ios也提供了类似这样的机制,这就是NSRunLoop了,当NSRunLoop运行起来后,他就会类似上面那段代码那样工作,当有数据源或timer事件向它发送消息的时候,线程就会被唤醒工作,调用我们注册的handler(函数)去执行我们自定义的任务。就像上面showView方法一样,方法里面新建了一个timer,timer会定时地在UIView上执行动画,然后把timer注册到主线程(主线程一般负载界面的更新和重绘)的NSRunLoop里面,所以每隔一定时间时,timer就能在主线程上执行动画

最后就是通过UIView来实现动画的绘制

-(void)beginAnimation{    [UIView animateWithDuration:AnimationTime delay:0 options:UIViewAnimationOptionCurveLinear animations:^{        UIView *dotView = _dotViews[_dotIndex];        [self moveDotViewToNextPosition:dotView];                _dotIndex ++;        _dotIndex = _dotIndex > 2 ? 0 : _dotIndex;            } completion:nil];}-(void)moveDotViewToNextPosition:(UIView*)dotView{    if (CGPointEqualToPoint(dotView.frame.origin, LeftTopPosition)) {        dotView.frame = (CGRect){LeftTBottomPosition, dotView.frame.size};    }    else if (CGPointEqualToPoint(dotView.frame.origin, LeftTBottomPosition)) {        dotView.frame = (CGRect){RightBottomPosition, dotView.frame.size};    }    else if (CGPointEqualToPoint(dotView.frame.origin, RightBottomPosition)) {        dotView.frame = (CGRect){RightTopPosition, dotView.frame.size};    }    else if (CGPointEqualToPoint(dotView.frame.origin, RightTopPosition)) {        dotView.frame = (CGRect){LeftTopPosition, dotView.frame.size};    }}



代码就分析完了,那总得练一下手,于是仿照上面的实现,我自己也些了一段小小的代码,实现的是一个指示器的功能,三个正方形轮流从左到右放大然后缩小



贴上完整的代码

#import "MyOwnView.h"#define AnimationTime 0.3#define TimerTime 0.5#define ViewSize (CGSizeMake(20, 20))#define View1Position (CGPointMake((self.frame.size.width / 4.0) * 1, 20))#define View2Position (CGPointMake((self.frame.size.width / 4.0) * 2, 20))#define View3Position (CGPointMake((self.frame.size.width / 4.0) * 3, 20))@interface MyOwnView()@property(nonatomic, strong) UIView* view1;@property(nonatomic, strong) UIView* view2;@property(nonatomic, strong) UIView* view3;@property(nonatomic, strong) NSArray *views;@property(nonatomic, strong) NSTimer* timer;@property(nonatomic, assign) int count;-(void)doAnimation;@end@implementation MyOwnView- (id)initWithFrame:(CGRect)frame{    self = [super initWithFrame:frame];    if (self) {    }    return self;}- (id)initWithCoder:(NSCoder *)aDecoder{    self = [super initWithCoder:aDecoder];    if (self) {        [self initViews];    }    return self;}- (void)initViews{    _view1 = [[UIView alloc]initWithFrame:(CGRect){View1Position, ViewSize}];    _view1.backgroundColor = [UIColor greenColor];    [self addSubview:_view1];    _view2 = [[UIView alloc]initWithFrame:(CGRect){View2Position, ViewSize}];    _view2.backgroundColor = [UIColor greenColor];    [self addSubview:_view2];    _view3 = [[UIView alloc]initWithFrame:(CGRect){View3Position, ViewSize}];    _view3.backgroundColor = [UIColor greenColor];    [self addSubview:_view3];    _views = @[_view1, _view2, _view3];}- (void)drawRect:(CGRect)rect{    NSLog(@"drawRect");}-(void)layoutSubviews{//    [self initViews];    NSLog(@"layoutSubviews");}-(void)showView:(BOOL)show{    if(show) {        _count = 0;        _timer = [NSTimer timerWithTimeInterval:0.5 target:self selector:@selector(doAnimation) userInfo:nil repeats:YES];        [[NSRunLoop mainRunLoop]addTimer:_timer forMode:NSDefaultRunLoopMode];    }else {        [_timer invalidate];    }}-(void)doAnimation{    UIView *view = [_views objectAtIndex:_count];    CGAffineTransform t = view.transform;        [UIView animateWithDuration:0.2 delay:0 options:UIViewAnimationOptionAutoreverse animations:^{        [view setTransform:CGAffineTransformScale(view.transform, 1.5, 1.5)];    } completion:^(BOOL finish){        [view setTransform:t];    }];        _count++;    _count = _count > 2 ? 0 : _count;}@end


0 0
原创粉丝点击