文章标题
2016-02-02 16:56
295 查看
http://ningandjiao.iteye.com/blog/2009542
http://my.oschina.net/u/1378445/blog/335014
最近在看Sam Davies写的iOS7系列文章(http://www.shinobicontrols.com/blog/posts/2013/09/19/introducing-ios7-day-by-day),非常有意思,以此为契机准备系统的学习一下iOS7的新特性, 今天是第一篇总结:UIDynamics。
UIDynamics的作用
在iOS7之前, 想要实现动画功能只有通过CoreAnimation或者UIView的Animation, 只能自己画, 对于一些真实世界中的动画行为,碰撞啊之类,实现起来特别复杂,而UIDynamic的引入就是为了简化这一类动画行为的。其将现实世界中各种物理动力驱动的动画引入了UIKit。(注:其只只引入了2D世界的物理引擎)。有了它之后,你会惊讶于可以通过如此少的代码实现这么复杂的动画效果。
UIDynamics的知识点
实例解析
下面我们就来实例解析下,如何通过UIDynamics实现一个牛顿摆(Newton’s Cradle), 实现后的效果如下:
在实现一个UIDynamic动画时, 首先需要把整个的动画过程分解到各个物理动力上, 实现一个牛顿摆的物理动力有:
1. 重力(UIGravityBehavior)
2. 球和锚点之间的牵引力(UIAttachmentBehavior)
3. 球与球之间的碰撞(UICollisionBehavior)
4. 空气阻力,摩擦力等(UIDynamicItemBehavior)
5. 手移动球时的推动力(UIPushBehavior)
分解完动力之后,来看代码实现:
首先,创建一个球,就是一个简单的UIView,设置下形状,颜色什么的:
Object-c代码 收藏代码
- (id)initWithFrame:(CGRect)frame
{
self = [super initWithFrame:frame];
if (self) {
self.backgroundColor = [UIColor yellowColor];
self.layer.cornerRadius = 10;
self.layer.borderColor = [UIColor redColor].CGColor;
self.layer.borderWidth = 3;
}
return self;
}
然后,创建牛顿摆的View,一个牛顿摆的界面设计的UI元素有3个, 球,锚点,球和描点的连接线,另外,为了实现UIDynamic的动画效果,需要一个UIDynamicAnimator来存储所有的DynamicBehavior,同时还有一个记录用户拉球的UIPushBehavior。
Object-c代码 收藏代码
//球的个数
NSUInteger ballCount;
//球和锚点
NSArray *_balls;
NSArray *_anchors;
UIDynamicAnimator *_animator;
UIPushBehavior *_userDragBehavior;
}
(id)initWithFrame:(CGRect)frame
{
self = [super initWithFrame:frame];
if (self) {
ballCount = 5;
//初始化球和锚点
[self createBallsAndAnchors];
//添加UIDynamics动力行为
[self applyDynamicBehaviors];
}
return self;
}
-(void)createBallsAndAnchors
{
NSMutableArray *ballsArray = [NSMutableArray array];
NSMutableArray *anchorsArray = [NSMutableArray array];
//估算球的大小,占屏1/3,处于屏幕中间方便用户玩
CGFloat ballSize = CGRectGetWidth(self.bounds)/(3.0*(ballCount-1));
}
(UIView )createAnchorForBall:(BallView )ball
{
CGPoint anchor = ball.center;
//根据球的位置确定描点的位置
anchor.y -= CGRectGetHeight(self.bounds) / 4.0;
UIView *blueBox = [[UIView alloc] initWithFrame:CGRectMake(0, 0, 10, 10)];
blueBox.backgroundColor = [UIColor blueColor];
blueBox.center = anchor;
return blueBox;
}
//处理拖动手势
-(void)handleBallPan:(UIPanGestureRecognizer *)recoginizer
{
//用户开始拖动时创建一个新的UIPushBehavior,并添加到animator中
if(recoginizer.state == UIGestureRecognizerStateBegan){
if (_userDragBehavior) {
[_animator removeBehavior:_userDragBehavior];
}
_userDragBehavior = [[UIPushBehavior alloc] initWithItems:@[recoginizer.view] mode:UIPushBehaviorModeContinuous];
[_animator addBehavior:_userDragBehavior];
}
}
{
//添加UIDynamic的动力行为,同时把多个动力行为组合为一个复杂的动力行为。
UIDynamicBehavior *behavior = [[UIDynamicBehavior alloc] init];
[self applyAttachBehaviorForBalls:behavior];
[behavior addChildBehavior:[self createGravityBehaviorForObjects:_balls]];
[behavior addChildBehavior:[self createCollisionBehaviorForObjects:_balls]];
[behavior addChildBehavior:[self createItemBehavior]];
_animator = [[UIDynamicAnimator alloc] initWithReferenceView:self];
[_animator addBehavior:behavior];
}
(void)applyAttachBehaviorForBalls:(UIDynamicBehavior *)behavior
{
//为每个球到对应的锚点添加一个AttachmentBehavior,并作为一个子Behavior添加到一个Behavior中。
for(int i=0; i
{
// Observer方法,当ball的center属性发生变化时,刷新整个view
[self setNeedsDisplay];
}
//覆盖父类的方法,主要是为了在锚点和球之间画一条线
-(void)drawRect:(CGRect)rect
{
CGContextRef context = UIGraphicsGetCurrentContext();
for(id ballBearing in _balls){
CGPoint anchor =[[_anchors objectAtIndex:[_balls indexOfObject:ballBearing]] center];
CGPoint ballCenter = [ballBearing center];
CGContextMoveToPoint(context, anchor.x, anchor.y);
CGContextAddLineToPoint(context, ballCenter.x, ballCenter.y);
CGContextSetLineWidth(context, 1.0f);
[[UIColor blackColor] setStroke];
CGContextDrawPath(context, kCGPathFillStroke);
}
[self setBackgroundColor:[UIColor whiteColor]];
}
//添加了Observer必须释放,不然会造成内存泄露。
-(void)dealloc
{
for (BallView *ball in _balls) {
[ball removeObserver:self forKeyPath:@”center”];
}
}
@end
把上面的2个View集合在一起,弄进一个App里就可以玩了。
http://my.oschina.net/u/1378445/blog/335014
最近在看Sam Davies写的iOS7系列文章(http://www.shinobicontrols.com/blog/posts/2013/09/19/introducing-ios7-day-by-day),非常有意思,以此为契机准备系统的学习一下iOS7的新特性, 今天是第一篇总结:UIDynamics。
UIDynamics的作用
在iOS7之前, 想要实现动画功能只有通过CoreAnimation或者UIView的Animation, 只能自己画, 对于一些真实世界中的动画行为,碰撞啊之类,实现起来特别复杂,而UIDynamic的引入就是为了简化这一类动画行为的。其将现实世界中各种物理动力驱动的动画引入了UIKit。(注:其只只引入了2D世界的物理引擎)。有了它之后,你会惊讶于可以通过如此少的代码实现这么复杂的动画效果。
UIDynamics的知识点
实例解析
下面我们就来实例解析下,如何通过UIDynamics实现一个牛顿摆(Newton’s Cradle), 实现后的效果如下:
在实现一个UIDynamic动画时, 首先需要把整个的动画过程分解到各个物理动力上, 实现一个牛顿摆的物理动力有:
1. 重力(UIGravityBehavior)
2. 球和锚点之间的牵引力(UIAttachmentBehavior)
3. 球与球之间的碰撞(UICollisionBehavior)
4. 空气阻力,摩擦力等(UIDynamicItemBehavior)
5. 手移动球时的推动力(UIPushBehavior)
分解完动力之后,来看代码实现:
首先,创建一个球,就是一个简单的UIView,设置下形状,颜色什么的:
Object-c代码 收藏代码
- (id)initWithFrame:(CGRect)frame
{
self = [super initWithFrame:frame];
if (self) {
self.backgroundColor = [UIColor yellowColor];
self.layer.cornerRadius = 10;
self.layer.borderColor = [UIColor redColor].CGColor;
self.layer.borderWidth = 3;
}
return self;
}
然后,创建牛顿摆的View,一个牛顿摆的界面设计的UI元素有3个, 球,锚点,球和描点的连接线,另外,为了实现UIDynamic的动画效果,需要一个UIDynamicAnimator来存储所有的DynamicBehavior,同时还有一个记录用户拉球的UIPushBehavior。
Object-c代码 收藏代码
import “NewtonsCradleView.h”
@implementation NewtonsCradleView{//球的个数
NSUInteger ballCount;
//球和锚点
NSArray *_balls;
NSArray *_anchors;
UIDynamicAnimator *_animator;
UIPushBehavior *_userDragBehavior;
}
(id)initWithFrame:(CGRect)frame
{
self = [super initWithFrame:frame];
if (self) {
ballCount = 5;
//初始化球和锚点
[self createBallsAndAnchors];
//添加UIDynamics动力行为
[self applyDynamicBehaviors];
}
return self;
}
-(void)createBallsAndAnchors
{
NSMutableArray *ballsArray = [NSMutableArray array];
NSMutableArray *anchorsArray = [NSMutableArray array];
//估算球的大小,占屏1/3,处于屏幕中间方便用户玩
CGFloat ballSize = CGRectGetWidth(self.bounds)/(3.0*(ballCount-1));
for(int i=0; i<ballCount; i++) { BallView *ball = [[BallView alloc] initWithFrame:CGRectMake(0, 0, ballSize-1, ballSize-1)]; CGFloat x = CGRectGetWidth(self.bounds)/3.0+i*ballSize; CGFloat y = CGRectGetHeight(self.bounds)/1.5; ball.center = CGPointMake(x, y); //为球添加UIPushBehavior,支持用户拖动 UIPanGestureRecognizer *panGesture = [[UIPanGestureRecognizer alloc] initWithTarget:self action:@selector(handleBallPan:)]; [ball addGestureRecognizer:panGesture]; //为球添加Oberser,当球的center属性发生改变时,会通知UIView的方法,刷新view,这儿主要是为了在球移动的时候保持锚点和球之间的连接线。 [ball addObserver:self forKeyPath:@"center" options:NSKeyValueObservingOptionNew context:Nil]; [ballsArray addObject:ball]; [self addSubview:ball]; UIView *blueBox = [self createAnchorForBall:ball]; [anchorsArray addObject:blueBox]; [self addSubview:blueBox]; } _balls = ballsArray; _anchors = anchorsArray;
}
(UIView )createAnchorForBall:(BallView )ball
{
CGPoint anchor = ball.center;
//根据球的位置确定描点的位置
anchor.y -= CGRectGetHeight(self.bounds) / 4.0;
UIView *blueBox = [[UIView alloc] initWithFrame:CGRectMake(0, 0, 10, 10)];
blueBox.backgroundColor = [UIColor blueColor];
blueBox.center = anchor;
return blueBox;
}
//处理拖动手势
-(void)handleBallPan:(UIPanGestureRecognizer *)recoginizer
{
//用户开始拖动时创建一个新的UIPushBehavior,并添加到animator中
if(recoginizer.state == UIGestureRecognizerStateBegan){
if (_userDragBehavior) {
[_animator removeBehavior:_userDragBehavior];
}
_userDragBehavior = [[UIPushBehavior alloc] initWithItems:@[recoginizer.view] mode:UIPushBehaviorModeContinuous];
[_animator addBehavior:_userDragBehavior];
}
//用户完成拖动时,从animator移除PushBehavior _userDragBehavior.pushDirection = CGVectorMake([recoginizer translationInView:self].x/10.f, 0); if (recoginizer.state == UIGestureRecognizerStateEnded) { [_animator removeBehavior:_userDragBehavior]; _userDragBehavior = nil; }
}
pragma mark - UIDynamics utility methods
(void)applyDynamicBehaviors{
//添加UIDynamic的动力行为,同时把多个动力行为组合为一个复杂的动力行为。
UIDynamicBehavior *behavior = [[UIDynamicBehavior alloc] init];
[self applyAttachBehaviorForBalls:behavior];
[behavior addChildBehavior:[self createGravityBehaviorForObjects:_balls]];
[behavior addChildBehavior:[self createCollisionBehaviorForObjects:_balls]];
[behavior addChildBehavior:[self createItemBehavior]];
_animator = [[UIDynamicAnimator alloc] initWithReferenceView:self];
[_animator addBehavior:behavior];
}
(void)applyAttachBehaviorForBalls:(UIDynamicBehavior *)behavior
{
//为每个球到对应的锚点添加一个AttachmentBehavior,并作为一个子Behavior添加到一个Behavior中。
for(int i=0; i
pragma mark - Observer
-(void)observeValueForKeyPath:(NSString )keyPath ofObject:(id)object change:(NSDictionary )change context:(void *)context{
// Observer方法,当ball的center属性发生变化时,刷新整个view
[self setNeedsDisplay];
}
//覆盖父类的方法,主要是为了在锚点和球之间画一条线
-(void)drawRect:(CGRect)rect
{
CGContextRef context = UIGraphicsGetCurrentContext();
for(id ballBearing in _balls){
CGPoint anchor =[[_anchors objectAtIndex:[_balls indexOfObject:ballBearing]] center];
CGPoint ballCenter = [ballBearing center];
CGContextMoveToPoint(context, anchor.x, anchor.y);
CGContextAddLineToPoint(context, ballCenter.x, ballCenter.y);
CGContextSetLineWidth(context, 1.0f);
[[UIColor blackColor] setStroke];
CGContextDrawPath(context, kCGPathFillStroke);
}
[self setBackgroundColor:[UIColor whiteColor]];
}
//添加了Observer必须释放,不然会造成内存泄露。
-(void)dealloc
{
for (BallView *ball in _balls) {
[ball removeObserver:self forKeyPath:@”center”];
}
}
@end
把上面的2个View集合在一起,弄进一个App里就可以玩了。
相关文章推荐
- thinkphp整合bootstrap分页
- 360奇酷手机显示Log
- 从头认识Spring-1.14 SpEl表达式(2)-嵌入Bean、Bean的属性和Bean的方法
- android中Logcat的深层理解
- 源代码管理的一些问题
- 微信公众号变现方式
- PL/SQL编程学习之异常处理
- android事件传递
- linux运维实战练习-2016年1月19日-2月3日课程作业(练习)安排
- css+div 导航条如何横着放
- Treap的读书笔记2
- css3 动画应用 animations 和transtions transform在加上JavaScript 可以实现硬件加速动画。
- ios学习:页面跳转(present)
- AWK学习笔记
- python 动态加载module、class、function
- Linux 用户空间与内核空间数据交换方式
- 《环信支持千万并发即使通讯的技术要点》阅读摘要
- 用Zoho People实时收到HR消息和动态提醒
- Python开发环境配置:Eclipse+PyDev
- 博客美化