动画特效九:下拉刷新
来源:互联网 发布:网络主播杨博在哪直播 编辑:程序博客网 时间:2024/06/05 00:41
这一节为大家介绍一个常用的操作:下拉刷新。我这里的Demo,是模拟情况,没有涉及到具体的数据源。真实的下拉刷新控件还是比较复杂的。先看看效果图。
关于UITableView的代码就忽略不计了,那不是本节讲解的重点。
动画分析:
1. UITableView上方有一个View,就是用来展示下拉刷新的特效的,所以完全可以自定义一个View来封装它,我将其命名为RefreshView。
2. 自定义的View上面有两个图层动画(1. 转圈圈;2. 飞机旋转), 所以可以自定义两个图层:ovalShapeLayer和airplaneLayer。
3. 由于自定义的View中,要判断scrollView的拖拽等功能,所以要将UITableView传递过来,并且自己实现UIScrollViewDelegate协议。
代码分析:
1. RefreshView.h ,初始化RefreshView的frame及将UITableView传递过来。
@interface RefreshView : UIView- (instancetype)initWithFrame:(CGRect)frame scrollView:(UIScrollView *)scrollView;@end
2. RefreshView.m 属性定义部分
@interface RefreshView()<UIScrollViewDelegate>/*主界面传递过来的scrollView*/@property (nonatomic, strong) UIScrollView *scrollView;/*转圈圈的shapeLayer*/@property (nonatomic, strong) CAShapeLayer *ovalShapeLayer;/*飞机的layer*/@property (nonatomic, strong) CALayer *airplaneLayer;@end
3. initWithFrame:scrollView的实现代码
- (instancetype)initWithFrame:(CGRect)frame scrollView:(UIScrollView *)scrollView { if (self = [super initWithFrame:frame]) { self.scrollView = scrollView; self.scrollView.delegate = self; [self addBgImage]; } return self;}- (void)addBgImage { UIImageView *bgImageView = [[UIImageView alloc] init]; bgImageView.image = [UIImage imageNamed:@"refresh-view-bg.png"]; bgImageView.frame = self.bounds; bgImageView.contentMode = UIViewContentModeScaleAspectFill; bgImageView.clipsToBounds = YES; [self addSubview:bgImageView];}
然后在ViewController中初始化RefreshView。
- (void)viewDidLoad { [super viewDidLoad]; CGRect refreshViewFrame = CGRectMake(0, -kRefreshViewHeight, self.view.frame.size.width, kRefreshViewHeight); self.refreshView = [[RefreshView alloc] initWithFrame:refreshViewFrame scrollView:self.tableView]; [self.tableView addSubview:self.refreshView]; self.tableView.contentOffset = CGPointMake(0, kRefreshViewHeight);}
注意到 kRefreshViewHeight是一个宏,其就是RefreshView的实际高度
#define kRefreshViewHeight 110.0而且它的frame的y值是负数,所以默认情况下,它是看不见,当你将UITableView往下拉的时候,便可以看见。
至此,效果图如下:
4. 添加圆环转圈圈动画。
在initWithFrame:scrollView方法的底部添加如下代码:
- (void)addOvalShapeLayer { self.ovalShapeLayer = [CAShapeLayer layer]; self.ovalShapeLayer.strokeColor = [UIColor whiteColor].CGColor; self.ovalShapeLayer.fillColor = [UIColor clearColor].CGColor; self.ovalShapeLayer.lineWidth = 4.0; self.ovalShapeLayer.lineDashPattern = @[@(2),@(3)]; CGFloat refreshRadius = self.frame.size.height / 2 * 0.8; self.ovalShapeLayer.path = [UIBezierPath bezierPathWithOvalInRect: CGRectMake(self.frame.size.width / 2 - refreshRadius, self.frame.size.height / 2 - refreshRadius, 2 * refreshRadius, 2 *refreshRadius)].CGPath; [self.layer addSublayer:self.ovalShapeLayer];}对lineDashPattern进行说明,注意到,它是一个数组并且有两个值。第一个值表示每段圆圈的宽度,第二个值表示段与段之间的距离。我们看看效果图:
在initWithFrame:scrollView方法的底部添加如下代码:
- (void)addAirplaneLayer { self.airplaneLayer = [CALayer layer]; self.airplaneLayer.opacity = 0.0; UIImage *image = [UIImage imageNamed:@"airplane.png"]; self.airplaneLayer.contents = (__bridge id)(image.CGImage); self.airplaneLayer.frame = CGRectMake(0, 0, image.size.width, image.size.height); self.airplaneLayer.position = CGPointMake(self.frame.size.width / 2 + self.frame.size.height / 2 * 0.8, self.frame.size.height / 2); [self.layer addSublayer:self.airplaneLayer];}
这样飞机就出现在圆圈的右侧了。紧接着,我们为圆环及飞机添加动画效果。
先看看圆圈的动画效果。注意到,当你将scrollView网下拉的时候,圆圈的白色就越来越多;当往上拉的时候,圆圈的白色就越来越少。而这个效果可以通过ovalshapeLayer的strokeEnd属性值来控制。strokeEnd的取值范围是(0.0~1.0),当为0.0的时候,看不到圆圈;当为1.0的时候,整个圆圈显示完整;当为0.25和0.50的时候,效果图分别如下:
所以,我们在代码方法中写入以下代码,便可以看出圆圈的即时变化
// 拖动tableview的时候,就显示圆圈增加或者减少效果(在scrollView拖拽过程中会一直触发)- (void)scrollViewDidScroll:(UIScrollView *)scrollView { // scrollView.contentOffset.y 往下拉值为负,往上提值为正 CGFloat offsetY = MAX(-(scrollView.contentOffset.y + scrollView.contentInset.top), 0); self.progress = MIN(MAX(offsetY / self.frame.size.height, 0), 1); [self redrawFromProgress:self.progress];}
- (void)redrawFromProgress:(CGFloat)progress { self.ovalShapeLayer.strokeEnd = progress; // 伴随着滚动,有种透明的效果 self.airplaneLayer.opacity = progress;}
注意到progress属性,它就是用来保存用户将RefreshView拖动到的位置,它的值的范围(0.0~1.0)
/*拉动的距离(0~1)*/@property (nonatomic, assign) CGFloat progress;由于有动画的开始和结束相应的操作,所以我定义一个bool变量,用来判断对应的状态
/*是否正在刷新*/@property (nonatomic, assign, getter=isRefreshing) BOOL refreshing;
5. 当用户拉动scrollView并且拖拽的范围使得RefreshView完全可见,也就是self.progress的值为1的时候,应该执行刷新操作。实际情况下,这个时候应该进行完成网络数据的加载,我这里用延时4秒,仿真加载数据。
代码如下:
// 在scrollView停止拖拽的时候会触发- (void)scrollViewWillEndDragging:(UIScrollView *)scrollView withVelocity:(CGPoint)velocity targetContentOffset:(inout CGPoint *)targetContentOffset { if (!self.isRefreshing && self.progress >= 1.0) { [self beginRefreshing]; }}
- (void)beginRefreshing { self.refreshing = YES; [UIView animateWithDuration:4.0 animations:^{ UIEdgeInsets newInsets = self.scrollView.contentInset; newInsets.top += self.frame.size.height; self.scrollView.contentInset = newInsets; } completion:^(BOOL finished) { [self endRefreshing]; }]; // 圆圈效果 CABasicAnimation *strokeStartAnimation = [CABasicAnimation animationWithKeyPath:@"strokeStart"]; strokeStartAnimation.fromValue = @(-0.5); strokeStartAnimation.toValue = @(1.0); CABasicAnimation *strokeEndAnimation = [CABasicAnimation animationWithKeyPath:@"strokeEnd"]; strokeEndAnimation.fromValue = @(0.0); strokeEndAnimation.toValue = @(1.0); CAAnimationGroup *strokeAnimationGroup = [CAAnimationGroup animation]; strokeAnimationGroup.duration = 1.5; strokeAnimationGroup.repeatDuration = 6.0; strokeAnimationGroup.animations = @[strokeStartAnimation, strokeEndAnimation]; [self.ovalShapeLayer addAnimation:strokeAnimationGroup forKey:nil]; // 飞机效果 // 1. 绕着圆圈移动 CAKeyframeAnimation *flightAnimation = [CAKeyframeAnimation animationWithKeyPath:@"position"]; flightAnimation.path = self.ovalShapeLayer.path; flightAnimation.calculationMode = kCAAnimationPaced; // 2. 有转动效果 CABasicAnimation *airplaneOrientationAnimation = [CABasicAnimation animationWithKeyPath:@"transform.rotation"]; airplaneOrientationAnimation.fromValue = @0; airplaneOrientationAnimation.toValue = @(2 * M_PI); CAAnimationGroup *flightAnimationGroup = [CAAnimationGroup animation]; flightAnimationGroup.duration = 1.5; flightAnimationGroup.repeatDuration = 6.0; flightAnimationGroup.animations = @[flightAnimation,airplaneOrientationAnimation]; [self.airplaneLayer addAnimation:flightAnimationGroup forKey:nil];}- (void)endRefreshing { self.refreshing = NO; [UIView animateWithDuration:0.3 delay:0.0 options:UIViewAnimationOptionCurveEaseOut animations:^{ UIEdgeInsets newInsets = self.scrollView.contentInset; newInsets.top -= self.frame.size.height; self.scrollView.contentInset = newInsets; } completion:nil];}
- 动画特效九:下拉刷新
- 下拉刷新特效EGOTableViewPullRefresh
- Android 特效库 - 下拉刷新
- 下拉刷新动画研究
- 仿美团下拉刷新动画
- 仿京东下拉刷新动画
- 动画特效十:下拉放大
- PullToRrefresh自定义下拉刷新动画
- 修改PullToRefresh下拉刷新动画
- Android的下拉刷新动画
- PullToRrefresh自定义下拉刷新动画
- PullToRrefresh自定义下拉刷新动画
- PullToRrefresh自定义下拉刷新动画
- android下拉刷新精彩动画
- PullToRrefresh自定义下拉刷新动画
- tableView 下拉刷新动画demo
- MJRefresh实现动画下拉刷新
- PullToRrefresh自定义下拉刷新动画
- 经验分享:多屏复杂动画CSS技巧三则
- @property定义的成员变量
- 安卓应用打包和安装的过程
- 编程技巧 - 2
- 内核点滴——delalloc
- 动画特效九:下拉刷新
- Android恶意代码分析与渗透测试
- 简单并查集之带权并查集HDU3038 How Many Answers Are Wrong
- 泰课在线Unity3d 动作游戏全攻略
- HDU 1865 1sting
- 提高iOS开发效率的方法和工具
- java视频教程免费下载
- Hadoop、Spark、HBase与Redis的适用性见解
- c语言生成静态库.a和动态库.so