iOS进阶 - UIDynamic

来源:互联网 发布:知无涯者 电影下载 编辑:程序博客网 时间:2024/05/21 20:21

一、简单概述

1.什么是UIDynamic

UIDynamic是从iOS 7开始引入的一种新技术,隶属于UIKit框架 ,可以认为是一种物理引擎,能模拟和仿真现实生活中的物理现象 如:重力、弹性碰撞等现象

其实就是UIKit的一套动画和交互体系。我们现在进行UI动画基本都是使用CoreAnimation或者UIView animations。而UIKit动力学最大的特点是将现实世界动力驱动的动画引入了UIKit,比如重力,铰链连接,碰撞,悬挂等效果。总之就是,将2D物理引擎引入了人UIKit。需要注意,UIKit动力学的引入,并不是以替代CA或者UIView动画为目的的,在绝大多数情况下CA或者UIView动画仍然是最优方案,只有在需要引入逼真的交互设计的时候,才需要使用UIKit动力学它是作为现有交互设计和实现的一种补充而存在的。


UIKit Dynamic构架图

2.相关的基本概念

UIDynamicAnimator;动画的播放者,动力行为(UIDynamicBehavior)的容器,添加到容器内的行为将发挥作用;

UIDynamicBehavior:动力行为的描述,用来指定UIDynamicItem应该如何运动,即定义适用的物理规则。一般我们使用这个类的子类对象来对一组UIDynamicItem应该遵守的行为规则进行描述;

UIDynamicItem:用来描述一个力学物体的状态,其实就是实现了UIDynamicItem委托的对象,或者抽象为有面积有旋转的质点;

ReferenceView:等同于力学参考系,如果你的初中物理不是语文老师教的话,我想你知道这是啥..只有当想要添加力学的UIView是ReferenceView的子view时,动力UI才发生作用。

3.UIDynamic的相关类

(1)UIDynamicAnimator(仿真器)

它代表着实现仿真行为的上下文(为实行仿真行为提供的场所)

 须知:它可以让物理仿真元素执行物理仿真行为

        它是UIDynamicAnimator类型的对象

1>初始化和管理一个 Dynamic Animator

// 传入一个 Reference view创建一个 Dynamic Animator- (instancetype)initWithReferenceView:(UIView*)view;   //view参数:是一个参照视图,表示物理仿真的范围// 获取在 CGRect 内所有的动力项,这个 CGRect是基于 Reference view的二维坐标系统的- (NSArray*)itemsInRect:(CGRect)rect;//添加1个物理仿真行为- (void)addBehavior:(UIDynamicBehavior *)behavior;//移除1个物理仿真行为- (void)removeBehavior:(UIDynamicBehavior *)behavior;//移除之前添加过的所有物理仿真行为- (void)removeAllBehaviors;

2>获取 Dynamic Animator’s的状态

//是否正在进行物理仿真@property (nonatomic, readonly, getter = isRunning) BOOL running;// 获取所有的 Behaviors@property (nonatomic, readonly, copy) NSArray* behaviors;//获取参照视图  @property (nonatomic, readonly) UIView* referenceView;//这个 delegate中有两个回调方法,一个是在 animator暂停的时候调用,一个是在将要恢复的时候调用@property (nonatomic, assign) id <UIDynamicAnimatorDelegate> delegate;// 已经运行了多久的时间,是一个 NSTimeInterval- (NSTimeInterval)elapsedTime;//如果动力项不是通过 animator自动计算改变状态,比如,通过代码强制改变一个 item的 transfrom时,可以用这个方法通知 animator这个 item 的改变。如果不用这个方法,animator之后的动画会覆盖代码中对 item做的改变,相当于代码改变 transform变得没有意义。- (void)updateItemUsingCurrentState:(id <UIDynamicItem>)item;

3>Collection View Additions

- (instancetype)initWithCollectionViewLayout:(UICollectionViewLayout*)layout //传入一个 CollectionViewLayout创建一个 Dynamic Animator– layoutAttributesForCellAtIndexPath:– layoutAttributesForDecorationViewOfKind:atIndexPath:– layoutAttributesForSupplementaryViewOfKind:atIndexPath:

(2)UIDynamicBehavior(仿真行为)

1>主要的方法

//在将要进行动画时的 block回调@property(nonatomic, copy) void (^action)(void)//添加到该动态行为中的子动态行为@property(nonatomic, readonly, copy) NSArray *childBehaviors//  该动态行为相关联的dynamicAnimator@property(nonatomic, readonly) UIDynamicAnimator *dynamicAnimator

2>常用方法

//添加一个子动态行为- (void)addChildBehavior:(UIDynamicBehavior *)behavior// 移除一个子动态行为- (void)removeChildBehavior:(UIDynamicBehavior *)behavior// 当该动态行为将要被添加到一个UIDynamicAnimator中时,这个方法会被调用。- (void)willMoveToAnimator:(UIDynamicAnimator *)dynamicAnimator

注意:

 在开发中,大部分情况下使用 UIDynamicBehavior 的子类就足够了,因为UIKit 中已经有几个现成的模拟现实的 UIDynamicBehavior 类。

3>UIDynamicBehavior的子类,几种物理仿真行为

      UIGravityBehavior:重力行为

      UICollisionBehavior:碰撞行为

      UISnapBehavior:捕捉行为

      UIPushBehavior:推动行为

      UIAttachmentBehavior:附着行为

      UIDynamicItemBehavior:动力元素行为

  注意:上述所有物理仿真行为都继承自UIDynamicBehavior所有的UIDynamicBehavior都可以独立进行组合使用多种行为时,可以实现一些比较复杂的效果

二、使用方法

要想使用UIDynamic来实现物理仿真效果,大致的步骤如下

1)创建一个物理仿真器(顺便设置仿真范围)

2)创建相应的物理仿真行为(顺便添加物理仿真元素)

3)将物理仿真行为添加到物理仿真器中开始仿真

示例:

@interface DynamicItemBehavior ()@property(nonatomic) UIDynamicAnimator * dynmicAnimation;@property(nonatomic) UIImageView       * imageView;@end@implementation DynamicItemBehavior-(void)viewDidLoad{    [super viewDidLoad];    [self createUIDynmicAnimationObject];    [self createDynamicItemObject];    [self createUIDynamicBehaviorObject];}//第一步:创建UIDynamic Animation对象-(void)createUIDynmicAnimationObject{    UIDynamicAnimator * dynmicAnimation = [[UIDynamicAnimator alloc]initWithReferenceView:self.view];    //参数:ReferenceView表示一个参照视图,表示物理仿真的范围    self.dynmicAnimation = dynmicAnimation;}//第二步:创建任何遵守了UIDynamicItem协议的对象 UIView默认已经遵守了UIDynamicItem协议,因此任何UI控件都能做物理仿真-(void)createDynamicItemObject{    UIImageView * imageView = [[UIImageView alloc]initWithImage:[UIImage imageNamed:@"image"]];    self.imageView          = imageView;    imageView.frame         = CGRectMake(0, 0, 50, 50);    imageView.center        = self.view.center;    [self.view addSubview:imageView]; }//第三步:创建UIDynamicBehavior对象-(void)createUIDynamicBehaviorObject{   //UIDynamicBehavior的子类类型    UIGravityBehavior* gravityBeahvior = [[UIGravityBehavior alloc] initWithItems:@[_imageView]];    //将要实现的效果添加到仿真器中    [self.dynmicAnimation addBehavior:gravityBeahvior];}

三、相关说明

1.三个概念

1)谁要进行物理仿真?

    物理仿真元素(Dynamic Item

2)执行怎样的物理仿真效果?怎样的动画效果?

    物理仿真行为(Dynamic Behavior 

3)让物理仿真元素执行具体的物理仿真行为

    物理仿真器(Dynamic Animator 

2.物理仿真元素

(1)不是任何对象都能做物理仿真元素,不是任何对象都能进行物理仿真

(2)物理仿真元素要素:

任何遵守了UIDynamicItem协议的对象

UIView默认已经遵守了UIDynamicItem协议,因此任何UI控件都能做物理仿真

UICollectionViewLayoutAttributes类默认也遵守UIDynamicItem协议

四、相关UIDynamicBehavior的子类介绍

1.UIGravityBehavior_重力

重力行为,可以指定重力的方向和大小。用gravityDirection指定一个向量,或者设置 angle 和 magnitude。

(1)相关属性

// 添加到重力行为中的所有物理仿真元素@property (nonatomic, readonly, copy) NSArray* items;//运动方向,默认是(0.0f, 1.0f)。dx为-1.0f时向左运动,dy为-1.0时向上运动,所以根据0.0~1.0可以定位所有的方向。@property (readwrite, nonatomic) CGVector gravityDirection;// 重力方向(是一个角度,以x轴正方向为0°,顺时针正数,逆时针负数)@property (readwrite, nonatomic) CGFloat angle;// 量级(用来控制加速度,1.0代表加速度是1000 points /second²)@property (readwrite, nonatomic) CGFloat magnitude;

解释:

vector就是一个点,从坐标原点向这个点连线就是一个矢量,也就是重力的方向,默认是(0.0, 1.0)。这个属性的数据量很丰富,由这个点向X轴和Y轴分别做垂线构成了一个矩形,对角线与X轴夹角就是重力加速度的方向,即angle,对角线的长度就是重力加速度的值,即magnitude。也就是说我们完全可以用gravityDirection变量确定angle和magnitude的值,反之用angle和magnitude也可以确定gravityDirection的值。

(2)常用方法

//初始化方法 - (instancetype)initWithItems:(NSArray<id <UIDynamicItem>> *)items NS_DESIGNATED_INITIALIZER;//参数:items是实现UIDynamicItem委托协议的对象- (void)addItem:(id <UIDynamicItem>)item;  //添加一个物理仿真对象- (void)removeItem:(id <UIDynamicItem>)item; //删除一个物理仿真对象- (void)setAngle:(CGFloat)angle magnitude:(CGFloat)magnitude;  //动态设置重力加速度方向和重力加速度的大小

(3)示例

- (void)viewDidAppear:(BOOL)animated {    [super viewDidAppear:animated];    UIGravityBehavior *gravity = [[UIGravityBehavior alloc] initWithItems:@[self.squareView]]; // 创建一个重力行为    gravity.gravityDirection = CGVectorMake(0, 1); // 在垂直向下方向 1000 点/平方秒 的速度    [self.animator addBehavior:gravity];}

运行项目可以看到效果:

2.UICollisionBehavior_碰撞,弹力

碰撞行为,指定一个边界,物体在到达这个边界的时候会发生碰撞行为。通过实现 UICollisionBehaviorDelegate 可以跟踪物体什么时候开始碰撞和结束碰撞。

(1)相关属性

@property (nonatomic, readonly, copy) NSArray<id <UIDynamicItem>> *items; //碰撞行为数组@property (nonatomic, readwrite) UICollisionBehaviorMode collisionMode;//碰撞模式(分三种,           UICollisionBehaviorModeItems        = 1 << 0,元素碰撞        UICollisionBehaviorModeBoundaries   = 1 << 1,边界碰撞        UICollisionBehaviorModeEverything   = NSUIntegerMax全体碰撞)@property (nonatomic, readwrite) BOOL translatesReferenceBoundsIntoBoundary;//是否以参照视图的bounds为边界@property (nullable, nonatomic, weak, readwrite) id <UICollisionBehaviorDelegate> collisionDelegate;//代理@property (nullable, nonatomic, readonly, copy) NSArray<id <NSCopying>> *boundaryIdentifiers;//

(2)常用的方法

- (instancetype)initWithItems:(NSArray<id <UIDynamicItem>> *)items;//初始化方法- (void)addItem:(id <UIDynamicItem>)item;//添加一个物理仿真对象- (void)removeItem:(id <UIDynamicItem>)item;//移除一个物理仿真对象- (void)removeAllBoundaries;//移除所有边界- (void)removeBoundaryWithIdentifier:(id <NSCopying>)identifier; //移除ID对应的边界 - (UIBezierPath*)boundaryWithIdentifier:(id <NSCopying>)identifier; //通过ID找到边界路径- (void)addBoundaryWithIdentifier:(id <NSCopying>)identifier forPath:(UIBezierPath *)bezierPath;//添加一个path作为碰撞边界- (void)addBoundaryWithIdentifier:(id <NSCopying>)identifier fromPoint:(CGPoint)p1 toPoint:(CGPoint)p2;//通过添加两个点连成的线 作为边界- (nullable UIBezierPath *)boundaryWithIdentifier:(id <NSCopying>)identifier;//添加一个贝塞尔曲线路径的边界 - (void)setTranslatesReferenceBoundsIntoBoundaryWithInsets:(UIEdgeInsets)insets;//

(3)代理方法

//两个元素相互碰撞// item 与 item 之间开始碰撞- (void)collisionBehavior:(UICollisionBehavior *)behavior beganContactForItem:(id <UIDynamicItem>)item1 withItem:(id <UIDynamicItem>)item2 atPoint:(CGPoint)p;// item 与 item 之间结束碰撞- (void)collisionBehavior:(UICollisionBehavior *)behavior endedContactForItem:(id <UIDynamicItem>)item1 withItem:(id <UIDynamicItem>)item2;// item 和边界开始碰撞- (void)collisionBehavior:(UICollisionBehavior*)behavior beganContactForItem:(id <UIDynamicItem>)item withBoundaryIdentifier:(nullable id <NSCopying>)identifier atPoint:(CGPoint)p;// item 和边界结束碰撞- (void)collisionBehavior:(UICollisionBehavior*)behavior endedContactForItem:(id <UIDynamicItem>)item withBoundaryIdentifier:(nullable id <NSCopying>)identifier;

(3)示例

@interface  CollisionBehavior ()<UICollisionBehaviorDelegate>@property(nonatomic) UIDynamicAnimator * theAnimator;@property(nonatomic) UIImageView       * aimageView;@end@implementation CollisionBehavior-(void)viewDidLoad{    [super viewDidLoad];    self.aimageView = [[UIImageView alloc]initWithImage:[UIImage imageNamed:@"1"]];    self.aimageView.frame = CGRectMake(100, 100, 100, 100);    [self.view addSubview:self.aimageView];    self.theAnimator = [[UIDynamicAnimator alloc]initWithReferenceView:self.view];}-(void)viewDidAppear:(BOOL)animated{    [super viewDidAppear:animated];        UIGravityBehavior * gravity = [[UIGravityBehavior alloc]initWithItems:@[self.aimageView]];    [self.theAnimator addBehavior:gravity];        UICollisionBehavior * collsion = [[UICollisionBehavior alloc]initWithItems:@[self.aimageView]];    collsion.translatesReferenceBoundsIntoBoundary = YES;    collsion.collisionDelegate = self;    [self.theAnimator addBehavior:collsion];}#pragma --mark  Delegate-(void)collisionBehavior:(UICollisionBehavior *)behavior beganContactForItem:(id<UIDynamicItem>)item withBoundaryIdentifier:(id<NSCopying>)identifier atPoint:(CGPoint)p{    self.aimageView.image = [UIImage imageNamed:@"3"];}-(void)collisionBehavior:(UICollisionBehavior *)behavior endedContactForItem:(id<UIDynamicItem>)item withBoundaryIdentifier:(id<NSCopying>)identifier{    self.aimageView.image = [UIImage imageNamed:@"4"];}

现在运行项目将会看到如下效果:


3.UIAttachmentBehavior_吸附力

附着行为,让物体附着在某个点或另外一个物体上。可以设置附着点的到物体的距离,阻尼系数和振动频率等。
(1)相关属性

@property (readonly, nonatomic) UIAttachmentBehaviorType  attachedBehaviorType;// 吸附行为的类型typedef NS_ENUM(NSInteger, UIAttachmentBehaviorType) {UIAttachmentBehaviorTypeItems:表示连接两个item的吸附行为 UIAttachmentBehaviorTypeAnchor:表示连接一个item与锚点的吸附行为 } NS_ENUM_AVAILABLE_IOS(7_0);@property (readwrite, nonatomic) CGPoint anchorPoint;//锚点@property (readwrite, nonatomic) CGFloat length;// 吸附行为中的两个吸附点之间的距离,通常用这个属性来调整吸附的长度,可以创建吸附行为之后调用。系统基于你创建吸附行为的方法来自动初始化这个长度@property (readwrite, nonatomic) CGFloat damping; // // 描述吸附行为减弱的阻力大小,经测试,这个值越大,可以减震@property (readwrite, nonatomic) CGFloat frequency; //// 吸附行为震荡的频率 ,  该值越大,物理仿真元素运动越剧烈@property (readwrite, nonatomic) CGFloat frictionTorque NS_AVAILABLE_IOS(9_0);// 反抗旋转的程度 @property (readwrite, nonatomic) UIFloatRange attachmentRange NS_AVAILABLE_IOS(9_0);

(2)常用方法

initWithItem:attachedToAnchor:初始化连接动力item的中心和锚点的吸附行为- (instancetype)initWithItem:(id<UIDynamicItem>)item attachedToAnchor:(CGPoint)point参数:item是你要应用吸附行为的动力项,point是吸附行为的锚点,与跟行为相关的动态动画所在在系统坐标有关。返回:初始化的attachment behavior,如果初始化过程出错将会返回nil。该初始化方法的吸附行为的类型是 UIAttachmentBehaviorTypeAnchorinitWithItem:attachedToItem:初始化 连接两个动力项中心的 吸附行为 - (instancetype)initWithItem:(id<UIDynamicItem>)item1 attachedToItem:(id<UIDynamicItem>)item2参数:item1第一个被吸附行为连接的动力项,item2第二个被吸附行为连接的动力项返回:初始化的attachment behavior,如果初始化过程出错将会返回nil。该初始化方法的吸附行为的类型是UIAttachmentBehaviorTypeItemsinitWithItem:offsetFromCenter:attachedToAnchor:初始化 连接动力项中某一点和锚点的 吸附行为 - (instancetype)initWithItem:(id<UIDynamicItem>)item offsetFromCenter:(UIOffset)p1 attachedToAnchor:(CGPoint)point参数:item要应用吸附行为的动力项,p1相对于item中心的偏移,point 是吸附行为的锚点,与跟行为相关的动力动画所在在系统坐标有关。返回: 初始化的 attachment behavior,如果初始化过程出错将会返回nil。该初始化方法的吸附行为的类型是UIAttachmentBehaviorTypeAnchorinitWithItem:offsetFromCenter:attachedToItem:offsetFromCenter:初始化连接一个动力item中某一点和另一个动力item中某一点的吸附行为- (instancetype)initWithItem:(id<UIDynamicItem>)item1 offsetFromCenter:(UIOffset)p1 attachedToItem:(id<UIDynamicItem>)item2 offsetFromCenter:(UIOffset)p2参数:item1第一个被吸附行为连接的动力项,p1相对于item1中心的偏移,item2第二个被吸附行为连接的动力项,p2相对于item2中心的偏移返回:返回:初始化的attachment behavior,如果初始化过程出错将会返回nil。这是为UIAttachmentBehavior类指定的初始化程序。

(3)示例:

#import "AttachmentBehavior.h"@interface AttachmentBehavior ()@property(nonatomic) UIDynamicAnimator    * animator;@property(nonatomic) UIImageView          * imageView;@property(nonatomic) UIAttachmentBehavior * attachmentBehave;@end@implementation AttachmentBehavior-(void)viewDidLoad{    [super viewDidLoad];    [self createGeture];    [self addGravity];}-(void)createGeture{   UIPanGestureRecognizer * panGesture = [[UIPanGestureRecognizer alloc]                                          initWithTarget:self                                                  action:@selector(handleAttachmentGesture:)];   [self.view addGestureRecognizer:panGesture];}-(UIImageView *)imageView{    if (!_imageView) {        _imageView = [[UIImageView alloc]initWithImage:[UIImage imageNamed:@"1"]];        _imageView.frame =CGRectMake(100, 100, 50, 50);        [self.view addSubview:_imageView];    }    return _imageView;}-(void)addGravity{    self.animator = [[UIDynamicAnimator alloc]initWithReferenceView:self.view];    UICollisionBehavior * collsionBehaviour = [[UICollisionBehavior alloc]initWithItems:@[self.imageView]];    collsionBehaviour.translatesReferenceBoundsIntoBoundary = YES;    [self.animator addBehavior:collsionBehaviour];      UIGravityBehavior * gravityBehaviour = [[UIGravityBehavior alloc]initWithItems:@[self.imageView]];    [self.animator addBehavior:gravityBehaviour];}-(void)handleAttachmentGesture:(UIPanGestureRecognizer *)panGesture{    if (panGesture.state ==UIGestureRecognizerStateBegan) {        CGPoint imageViewCenterPoint =CGPointMake(self.imageView.center.x, self.imageView.center.y-100);               UIAttachmentBehavior * attachmentBehave = [[UIAttachmentBehavior alloc]initWithItem:self.imageView attachedToAnchor:imageViewCenterPoint ];        [self.animator addBehavior:attachmentBehave];        self.attachmentBehave = attachmentBehave;    }else if(panGesture.state ==UIGestureRecognizerStateChanged){        [self.attachmentBehave setAnchorPoint:[panGesture locationInView:self.view]];        }else if(panGesture.state ==UIGestureRecognizerStateEnded){        [self.animator removeBehavior:self.attachmentBehave];    }}@end

效果:


4.UIPushBehavior_推力

(1)相关属性

@property (nonatomic, readonly, copy) NSArray<id <UIDynamicItem>> *items;@property (nonatomic, readonly) UIPushBehaviorMode mode;// 推力模式{    UIPushBehaviorModeContinuous,//持续的力    UIPushBehaviorModeInstantaneous //一次性的力}@property (nonatomic, readwrite) BOOL active;//默认值是YES,将其设置为NO,可以将行为停止。在激活状态下,物体才会受到推力效果@property (readwrite, nonatomic) CGFloat angle;//角度@property (readwrite, nonatomic) CGFloat magnitude;//加速度@property (readwrite, nonatomic) CGVector pushDirection;//运动方向

(2)常见方法

- (instancetype)initWithItems:(NSArray<id <UIDynamicItem>> *)items mode:(UIPushBehaviorMode)mode;- (void)addItem:(id <UIDynamicItem>)item;- (void)removeItem:(id <UIDynamicItem>)item;- (UIOffset)targetOffsetFromCenterForItem:(id <UIDynamicItem>)item;//- (void)setTargetOffsetFromCenter:(UIOffset)o forItem:(id <UIDynamicItem>)item;//方法是说推力作用点的偏移量,默认是center。- (void)setAngle:(CGFloat)angle magnitude:(CGFloat)magnitude;//

(3)示例

#import "PushBehavior.h"@interface PushBehavior ()@property(nonatomic) UIDynamicAnimator * animator;@property(nonatomic) UIImageView * imageView;@end@implementation PushBehavior-(void)viewDidLoad{    [super viewDidLoad];    [self imageView];    [self createGesture];}-(void)createGesture{    UIPanGestureRecognizer * leftPanGesture = [[UIPanGestureRecognizer alloc]initWithTarget:self action:@selector(handlePanGesture:)];    [self.view addGestureRecognizer:leftPanGesture];}#pragma mark  --lasyLoad-(UIDynamicAnimator *)animator{    if (!_animator) {        _animator = [[UIDynamicAnimator alloc]initWithReferenceView:self.view];    }    return _animator;}-(UIImageView *)imageView{    if (!_imageView) {        _imageView = [[UIImageView alloc]initWithImage:[UIImage imageNamed:@"1"]];        _imageView.frame = CGRectMake(0, 0, 50,50);        _imageView.center = CGPointMake(self.view.bounds.size.width/2-100, self.view.bounds.size.height/2);        [self.view addSubview:_imageView];    }    return _imageView;}#pragma mark  --gesture触发方法-(void)handlePanGesture:(UIPanGestureRecognizer *)panGesture{    if (panGesture.state==UIGestureRecognizerStateEnded) {        if ([self  gestureHitsBarView:panGesture]) {            UIPushBehavior * pushBehavior = [[UIPushBehavior alloc]initWithItems:@[self.imageView] mode:UIPushBehaviorModeInstantaneous];            [pushBehavior setPushDirection:CGVectorMake([panGesture velocityInView:self.view].x /5000.f, 0)];            [self.animator removeAllBehaviors];            [self.animator addBehavior:pushBehavior];        }    }}-(BOOL)gestureHitsBarView:(UIPanGestureRecognizer *)panGesture{    CGPoint  locationInView =[panGesture locationInView:self.view];    return self.imageView.frame.origin.x <=locationInView.x &&locationInView.y<=self.imageView.frame.origin.y +self.imageView.frame.size.height;}@end

效果图:


5.UISnapBehavior_甩行力

将一个物体钉在某一点。它只有一个初始化方法和一个属性。

(1)相关属性

@property (nonatomic, assign) CGPoint snapPoint;@property (nonatomic, assign) CGFloat damping;//用于减幅、减震(取值范围是0.0 ~ 1.0,值越大,震动幅度越小)

(2)常见方法

- (instancetype)initWithItem:(id <UIDynamicItem>)item snapToPoint:(CGPoint)point;//初始化, 根据 item 和 point 来确定一个 item 要被定到哪个点上。

(3)示例

#import "ViewController.h"@interface ViewController ()@property(nonatomic) UIView * blueView;@property(nonatomic) UIDynamicAnimator * animator;@end@implementation ViewController- (void)viewDidLoad {    [super viewDidLoad];    UIView * View =({        UIView  * blueView = [[UIView alloc]initWithFrame:CGRectMake(100, 100, 100, 100)];        blueView.backgroundColor = [UIColor blueColor];        [self.view addSubview:blueView];        blueView;    });    self.blueView = View;}-(UIDynamicAnimator *)animator{    if (!_animator) {        _animator = [[UIDynamicAnimator alloc]initWithReferenceView:self.view];    }    return _animator;}-(void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event{     //获取一个触摸点    UITouch * touch = [touches anyObject];    CGPoint point = [touch locationInView:self.view];        UISnapBehavior * snap =[[UISnapBehavior alloc]initWithItem:self.blueView snapToPoint:point];    snap.damping = arc4random_uniform(10)/10.0;        [self.animator removeAllBehaviors];    [self.animator addBehavior:snap];}

效果图:


6.UIDynamicItemBehavior _自定义行为

(1)相关属性

@property (nonatomic, readonly, copy) NSArray<id <UIDynamicItem>> *items;@property (readwrite, nonatomic) CGFloat elasticity; // Usually between 0 (inelastic) and 1 (collide elastically) //(弹性系数)决定了碰撞的弹性程度,比如碰撞时物体的弹性@property (readwrite, nonatomic) CGFloat friction; // 0 being no friction between objects slide along each other.//(摩擦系数)决定了沿接触面滑动时的摩擦力大小@property (readwrite, nonatomic) CGFloat density; // 1 by default//(密度) 跟size结合使用,计算物体的总质量。质量越大,物体加速或减速就越困难@property (readwrite, nonatomic) CGFloat resistance; // 0: no velocity damping //(阻力):决定线性移动的阻力大小,与摩擦系数不同,摩擦系数只作用于滑动运动@property (readwrite, nonatomic) CGFloat angularResistance; // 0: no angular velocity damping  //(角阻力) :决定旋转运动时的阻力大小@property (readwrite, nonatomic) CGFloat charge NS_AVAILABLE_IOS(9_0);@property (nonatomic, getter = isAnchored) BOOL anchored NS_AVAILABLE_IOS(9_0);@property (readwrite, nonatomic) BOOL allowsRotation; // force an item to never rotate ////(允许旋转):这个属性很有意思,它在真实的物理世界没有对应的模型。设置这个属性为 NO 物体就完全不会转动,而无论施加多大的转动力

(2)常见方法

- (instancetype)initWithItems:(NSArray<id <UIDynamicItem>> *)items NS_DESIGNATED_INITIALIZER;- (void)addItem:(id <UIDynamicItem>)item;- (void)removeItem:(id <UIDynamicItem>)item;- (void)addLinearVelocity:(CGPoint)velocity forItem:(id <UIDynamicItem>)item;- (CGPoint)linearVelocityForItem:(id <UIDynamicItem>)item;- (void)addAngularVelocity:(CGFloat)velocity forItem:(id <UIDynamicItem>)item;- (CGFloat)angularVelocityForItem:(id <UIDynamicItem>)item;

(3)示例:

#import "PushBehavior.h"@interface PushBehavior ()@property(nonatomic) UIDynamicAnimator * animator;@end@implementation PushBehavior-(void)viewDidLoad{    [super viewDidLoad];}- (UIView *) newViewWithCenter:(CGPoint)paramCenter  backgroundColor:(UIColor *)paramBackgroundColor{    UIView *newView = [[UIView alloc] initWithFrame: CGRectMake(0.0f, 0.0f, 50.0f, 50.0f)];    newView.backgroundColor = paramBackgroundColor;    newView.center = paramCenter;    return newView;}- (void)viewDidAppear:(BOOL)animated{    [super viewDidAppear:animated];        UIView *topView = [self newViewWithCenter:CGPointMake(100.0f, 0.0f)                              backgroundColor:[UIColor greenColor]];    UIView *bottomView = [self newViewWithCenter:CGPointMake(100.0f, 50.0f)                                 backgroundColor:[UIColor redColor]];        [self.view addSubview:topView];    [self.view addSubview:bottomView];        //构造动画    self.animator = [[UIDynamicAnimator alloc] initWithReferenceView:self.view];        //gravity    UIGravityBehavior *gravity = [[UIGravityBehavior alloc]                                  initWithItems:@[topView, bottomView]];    [self.animator addBehavior:gravity];        //collision    UICollisionBehavior *collision = [[UICollisionBehavior alloc]                                      initWithItems:@[topView, bottomView]];    collision.translatesReferenceBoundsIntoBoundary = YES;    [self.animator addBehavior:collision];        //指派不同特性值  弹性bounce    UIDynamicItemBehavior *moreElasticItem = [[UIDynamicItemBehavior alloc]                                              initWithItems:@[bottomView]];    moreElasticItem.elasticity = 1.0f;        UIDynamicItemBehavior *lessElasticItem = [[UIDynamicItemBehavior alloc]                                              initWithItems:@[topView]];    lessElasticItem.elasticity = 0.5f;    [self.animator addBehavior:moreElasticItem];    [self.animator addBehavior:lessElasticItem];    }@end
效果图:


五,总结

UIKit Dynamic 是 UIKit 的一部分,这意味着使用它不需要添加其它额外的framework,所以如果应用只支持 iOS 7 以上,可以在项目中多多使用,让应用中的动画效果瞬间提升好几个档次。


0 0
原创粉丝点击