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
- ios学习开源代码系列(一)LHLoadingView
- ios学习开源代码系列(二)ifengNewsOrderDemo
- libdvbpsi 源代码学习(一)
- Struts2 源代码学习 (一)
- spring源代码学习(一)
- 学习博客园开源代码笔记(一)
- shark工作流源代码学习(一)
- ACE5.5.1源代码学习笔记(一)
- shark工作流源代码学习(一)
- shark工作流源代码学习(一)
- shark工作流源代码学习(一)
- 超级玛丽HTML5源代码学习------(一)
- ios学习(一)
- iOS学习(一)
- (安全系列一)Android Apk反编译得到Java源代码
- J2ME系列学习(一)
- AXIS系列学习(一)
- JAVA3D学习系列(一)
- UVa 10033 - Interpreter
- 用JS获取地址栏参数的方法(超级简单)
- 新手必看,关于ARM的22个常用概念!
- 具体化生活
- 在 Eclipse 中结合 IBM WebSphere Application Server 使用
- ios学习开源代码系列(一)LHLoadingView
- Python--Socket样例
- 读书笔记
- 8259DMA interrupt
- 2014找工作总结-机会往往留给有准备的人
- 在OPENSSL编程中出现这个问题的解释
- linux下打包文件排除指定文件或目录
- IPC之FIFO
- hibernaet.hbm.xml配置文件