您的位置:首页 > 其它

文章标题

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代码 收藏代码

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里就可以玩了。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: