一.pop和Core Animation的区别

  1.Core Animation的动画只能添加到layer上

  2.pop的动画能添加到任何对象

  3.pop的底层并非基于Core Animation,是基于CADisplayLink

  4.Core Animation的动画仅仅是表象,并不会真正修改对象的frame/Size等值

  5.pop的动画实时修改对象的属性,真正的修改了对象的属性

二.简单结构

三.pop框架简单使用 -- pop不仅可以给layer添加动画,只要是UIView都可以添加动画

  1.给view添加动画

  2.给layer添加动画

四.项目中的动画效果实现

  1.利用pop框架做动画的时候,如果动画关系到了尺寸或者frame,刚开始控件的尺寸或者frame建议不要设置.有时候会出现问题,如下图.由于pop框架做动画是直接修改的属性,所以可以考虑在fromValue中设置尺寸.

  2.点击取消按钮的动画,实现思路--直接遍历了控制器中子控件,通过xib添加的控件最早,所以做动画的控件从第2个开始遍历

  3.监听按钮的点击 -- 要求是动画依次做完,最后处理对应的事件.

  难点:pop框架提供了动画完成的block,自己的目标就是在动画完成后执行相应的事件处理.例如:点击了'发段子'按钮,先做动画,动画完成,跳转到发段子的控制器.

  解决方案:抽取方法,将点击取消按钮的动画封装起来,并用block作为参数.点击取消按钮,不需要处理事件,那么block就为nil;如果点击'发段子'之类的按钮,将需要处理的代码用block封装.

  

 - (void)cancleWithBlock:(void(^)())btnClickBlock
{
// 点击了取消之后,动画的过程中就不要处理事件了
self.view.userInteractionEnabled = NO; for (int i = ; i < self.view.subviews.count; i++) { UIView *subView = self.view.subviews[i];
POPBasicAnimation *anim = [POPBasicAnimation animationWithPropertyNamed:kPOPViewCenter]; anim.toValue = [NSValue valueWithCGPoint:CGPointMake(subView.centerX, subView.centerY + ChaosScreenH)];
anim.beginTime = CACurrentMediaTime() + (i - ) * ChaosTimeInterval;
anim.duration = 0.25; [subView pop_addAnimation:anim forKey:nil];
// 监听最后一个view动画的完成
if (i == self.view.subviews.count - ) {
[anim setCompletionBlock:^(POPAnimation *anim, BOOL finished) { [self dismissViewControllerAnimated:NO completion:nil];
// 判断点击按钮后要执行的block是否为空
if (btnClickBlock) {
btnClickBlock();
}
}];
}
}
} - (IBAction)cancelClick {
[self cancleWithBlock:nil];
} - (void)buttonClick:(UIButton *)button
{
[self cancleWithBlock:^{
if (button.tag == ) {
ChaosLog(@"发视频");
} else if (button.tag == ){
ChaosLog(@"发图片");
} else if (button.tag == ){
ChaosLog(@"发段子");
} else if (button.tag == ){
ChaosLog(@"发声音");
}
}];
}

五.最后是项目中的代码

  

 #import "ChaosPublishViewController.h"
#import "ChaosVerticalButton.h" #import <POP.h> @interface ChaosPublishViewController () @end
@implementation ChaosPublishViewController static CGFloat const ChaosTimeInterval = 0.1;
static CGFloat const ChaosAnimSpeed = ; - (void)viewDidLoad {
[super viewDidLoad]; // 先让所有不能处理事件
self.view.userInteractionEnabled = NO;
// 数据
NSArray *images = @[@"publish-video", @"publish-picture", @"publish-text", @"publish-audio", @"publish-review", @"publish-offline"];
NSArray *titles = @[@"发视频", @"发图片", @"发段子", @"发声音", @"审帖", @"离线下载"]; // 设置按钮位置
CGFloat buttonW = ;
CGFloat buttonH = buttonW + ;
CGFloat startY = (ChaosScreenH - * buttonH) * 0.5;
CGFloat startX = ;
NSInteger maxCols = ; // 列数
CGFloat buttonMargin = (ChaosScreenW - * startX - maxCols * buttonW) / (maxCols - );
// 添加发布类别
for (int i = ; i < images.count; i++) {
ChaosVerticalButton *button = [[ChaosVerticalButton alloc] init];
// button.width = buttonW; // 用了pop后,直接修改了按钮的frame,这里可以先不用设置
// button.height = buttonH; // 设置了动画效果反而不好
[button setImage:[UIImage imageNamed:images[i]] forState:UIControlStateNormal];
[button setTitle:titles[i] forState:UIControlStateNormal];
[button setTitleColor:[UIColor blackColor] forState:UIControlStateNormal];
button.titleLabel.font = [UIFont systemFontOfSize:];
button.tag = i;
// 添加点击事件
[button addTarget:self action:@selector(buttonClick:) forControlEvents:UIControlEventTouchUpInside];
NSInteger btnRow = i / maxCols; // 按钮所在行
NSInteger btnCol = i % maxCols; // 按钮所在列
CGFloat buttonEndY = startY + btnRow * buttonH; // 按钮最终Y值
CGFloat buttonX = startX + btnCol * (buttonMargin + buttonW); // 按钮X值 [self.view addSubview:button]; // 设置动画
POPSpringAnimation *anim = [POPSpringAnimation animationWithPropertyNamed:kPOPViewFrame];
anim.fromValue = [NSValue valueWithCGRect:CGRectMake(buttonX, buttonEndY - ChaosScreenH, buttonW, buttonH)];
anim.toValue = [NSValue valueWithCGRect:CGRectMake(buttonX, buttonEndY, buttonW, buttonH)];
// anim.springBounciness = 8;
anim.springSpeed = ChaosAnimSpeed;
anim.beginTime = CACurrentMediaTime() + i * ChaosTimeInterval;
[button pop_addAnimation:anim forKey:nil];
} // 添加标语
[self setupSlogan];
} - (void)setupSlogan
{
// 添加标语
UIImageView *sloganImageView = [[UIImageView alloc] initWithImage:[UIImage imageNamed:@"app_slogan"]];
sloganImageView.y = -;
[self.view addSubview:sloganImageView]; CGFloat centerX = ChaosScreenW * 0.5;
CGFloat centerEndY = ChaosScreenH * 0.2;
CGFloat centerBeginY = centerEndY - ChaosScreenH;
// 设置动画
POPSpringAnimation *anim = [POPSpringAnimation animationWithPropertyNamed:kPOPViewCenter];
anim.fromValue = [NSValue valueWithCGPoint:CGPointMake(centerX, centerBeginY)];
anim.toValue = [NSValue valueWithCGPoint:CGPointMake(centerX, centerEndY)];;
// anim.springBounciness = 8;
anim.springSpeed = ChaosAnimSpeed;
anim.beginTime = CACurrentMediaTime() + * ChaosTimeInterval;
[anim setCompletionBlock:^(POPAnimation *anim, BOOL finished) {
// 动画完成恢复处理事件的能力
self.view.userInteractionEnabled = YES;
}];
[sloganImageView pop_addAnimation:anim forKey:nil];
} - (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event
{
[self cancleWithBlock:nil];
} - (void)cancleWithBlock:(void(^)())btnClickBlock
{
// 点击了取消之后,动画的过程中就不要处理事件了
self.view.userInteractionEnabled = NO; for (int i = ; i < self.view.subviews.count; i++) { UIView *subView = self.view.subviews[i];
POPBasicAnimation *anim = [POPBasicAnimation animationWithPropertyNamed:kPOPViewCenter]; anim.toValue = [NSValue valueWithCGPoint:CGPointMake(subView.centerX, subView.centerY + ChaosScreenH)];
anim.beginTime = CACurrentMediaTime() + (i - ) * ChaosTimeInterval;
anim.duration = 0.25; [subView pop_addAnimation:anim forKey:nil];
// 监听最后一个view动画的完成
if (i == self.view.subviews.count - ) {
[anim setCompletionBlock:^(POPAnimation *anim, BOOL finished) { [self dismissViewControllerAnimated:NO completion:nil];
// 判断点击按钮后要执行的block是否为空
if (btnClickBlock) {
btnClickBlock();
}
}];
}
}
} - (IBAction)cancelClick {
[self cancleWithBlock:nil];
} - (void)buttonClick:(UIButton *)button
{
[self cancleWithBlock:^{
if (button.tag == ) {
ChaosLog(@"发视频");
} else if (button.tag == ){
ChaosLog(@"发图片");
} else if (button.tag == ){
ChaosLog(@"发段子");
} else if (button.tag == ){
ChaosLog(@"发声音");
}
}];
} @end

iOS不得姐项目--pop框架的初次使用的更多相关文章

  1. iOS不得姐项目--appearance的妙用,再一次设置导航栏返回按钮,导航栏左右按钮的封装(巧用分类)

    一.UI_APPEARANCE_SELECTOR 彩票项目中appearance的用法一直没有搞明白,这次通过第二个项目中老师的讲解,更深一层次的了解到了很多关于appearance的作用以及使用方法 ...

  2. iOS不得姐项目--TabBar的重复点击实现当前模块刷新;状态栏点击实现当前模块回滚到最顶部

    一.实现功能:重复点击tabBar,刷新当前TableView,其余不受影响 <1>实现思路: 错误的方法: TabBar成为自己的代理,监听自己的点击--这种方法是不可取的,如果外面设置 ...

  3. iOS不得姐项目--精华模块上拉下拉的注意事项,日期显示,重构子控制器,计算cell的高度(只计算一次),图片帖子的显示

    一.上拉下拉注意事项 使用MJRefresh中的上拉控件自动设置透明 当请求下页数据通过page的时候,注意的是上拉加载更多数据失败的问题,下拉加载数据失败了,页数应该还原.或者是请求成功的时候再将页 ...

  4. iOS不得姐项目--推荐关注模块(一个控制器控制两个tableView),数据重复请求的问题,分页数据的加载,上拉下拉刷新(MJRefresh)

    一.推荐关注模块(一个控制器控制两个tableView) -- 数据的显示 刚开始加载数据值得注意的有以下几点 导航控制器会自动调整scrollView的contentInset,最好是取消系统的设置 ...

  5. iOS不得姐项目--封装状态栏指示器(UIWindow实现)

    一.头文件 #import <UIKit/UIKit.h> @interface ChaosStatusBarHUD : NSObject /** 显示成功信息 */ + (void)sh ...

  6. iOS不得姐项目--图片帖子模块,大图默认显示最顶部分的处理

    一.刚开始的处理,设置Mode属性(self.pictureImageView.contentMode = UIViewContentModeScaleAspectFill;) 和 Clip Subv ...

  7. iOS不得姐项目--登录模块的布局,设置文本框占位文字颜色,自定义内部控件竖直排列的按钮

    一.登录模块的布局 将一整部分切割成若干部分来完成,如图分成了三部分来完成 设置顶部状态栏为白色的方法 二.设置文本框占位文字颜色 <1>方法一与方法二实现原理是同一种,都是通过设置pla ...

  8. 手把手教你如何搭建iOS项目基本框架

    手把手教你如何搭建iOS项目基本框架 今天我们来谈谈如何搭建框架,框架需要做一些什么. 第一步:找到我们的目标我们的目标是让其他开发人员拿到手后即可写页面,不再需要考虑其他的问题. 第二步:我们需要做 ...

  9. iOS项目——基本框架搭建

    项目开发过程中,在完成iOS项目——项目开发环境搭建之后,我们首先需要考虑的就是我们的项目的整体框架与导航架构设计,然后在这个基础上考虑功能模块的完成. 一 导航架构设计 一款App的导航架构设计应该 ...

随机推荐

  1. Spring学习之AOP总结帖

    AOP(面向方面编程),也可称为面向切面编程,是一种编程范式,提供从另一个角度来考虑程序结构从而完善面向对象编程(OOP). 在进行 OOP 开发时,都是基于对组件(比如类)进行开发,然后对组件进行组 ...

  2. java 22 - 6 多线程之线程调度和设置线程的优先级

    线程调度 假如我们的计算机只有一个 CPU,那么 CPU 在某一个时刻只能执行一条指令,线程只有得到 CPU时间片,也就是使用权,才可以执行指令. 那么Java是如何对线程进行调用的呢? 线程有两种调 ...

  3. Java命令行的执行参数

    Java 程序命令行参数说明 启动Java程序的方式有两种: # starts a Java virtual machine, loads the specified class, and invok ...

  4. Java 日志性能优化

    1. 选择合理的日志级别.合理控制日志内容 2. 控制日志的输出内容和格式 logger.debug("Entry number: " + i + " is " ...

  5. ICC的sacn-wise和unit-wise

    假设有16个被试,2个session,2个RUN,200个ROI,那么ICC需要对RUN1和RUN2分别算两次(相比而言,paired ttest则是对一个session中的RUN1和RUN2计算) ...

  6. AngularJS中的指令

    欢迎大家讨论与指导 : )  前言 当AngularJS中的内置指令不能满足我们的需求,或者当我们需要创建一个能够用于多个AngularJS程序的自包含的功能单元时,我们应该创建自定义指令来满足需求. ...

  7. AlwaysOn Group Listener

    1.Listener是什么 Listener实际上是一个 VirtualNetworkName,客户端通过这个VNN来连接的具体的sqlserver实例 .Listener包含了DNS名称,port和 ...

  8. ELK+FileBeat+Log4Net

    ELK+FileBeat+Log4Net搭建日志系统 output { elasticsearch { hosts => ["localhost:9200"] } stdou ...

  9. android values目录的读取优先级

    android项目新建时会有一个values目录(高版本会增加values-v11,values-v14目录),该目录用于存放显示相的配置数据的定义文件,如strings.xml, style.xml ...

  10. web学习第一章

    web学习第一章   我是大概9月10日开始走上IT之路的,一开始学习了小段时间的自动化办公软件, 昨天我开始学习客户端网页编程,我了解什么是WEB,一些比较老古董的计算模式和发展历史,印象最让我深刻 ...