iOS干货iOS CoreAnimationtips

UIKit Dynamic基础

2016-01-11  本文已影响493人  Wang66

前言

iOS7在视觉元素上去除了拟物化,UI偏向了扁平化风格。但也从iOS7开始,iOS却在“物理”上拟真了,这儿指的是交互动画。比如,它能模拟自由落体,碰撞反弹,吸附等和现实物理现象一致的交互效果。


基础知识

** 关于碰撞行为的边界:**

translatesReferenceBoundsIntoBoundary将整个参照view(也就是self.view)的边框作为碰撞边界(另外你还可以使用setTranslatesReferenceBoundsIntoBoundaryWithInsets:这样的方法来设定某一个区域作为碰撞边界,更复杂的边界可以使用addBoundaryWithIdentifier:forPath:来添加UIBezierPath,或者addBoundaryWithIdentifier:fromPoint:toPoint:来添加一条线段为边界,详细地还请查阅文档)。

** 关于动力项行为:**

动力项行为(UIDynamicItemBehavior)和其他几个内置的行为不太一样,它用于对动力项赋物理属性值。比如,密度,速度,阻力等。

** 需要注意的是,我们知道,对某动力项移除普通动力行为后,该动力项目会立马停止动画。比如,正在下落的ImgView移除重力行为后,并没有继续随重力继续下落,而是当即停止下落。然而,若一个动力项拥有UIDynamicItemBehavior行为,即便移除了重力行为,该动力项还是会根据设置的物理属性来进行运动。在实践中,若想让我们的动力项表现得更“真实自然”,给他们附加一个空的UIDynamicItemBehavior会很有帮助。**


代码例子

下面代码创建了一个UIImageView,并为其添加了一个拖动手势,拖动手势的事件回调是为imgView添加了一个“吸附行为”;并为imgView添加了“重力行为”和“碰撞行为”,当拖动松开时,imgView便自由落体撞击“地面”;最后还给self.view添加了单击手势,其事件回调是为imgView添加了一个“瞬移行为”,点到self.view的某点,imgView就瞬移到该点。

** 注意:** 重力行为是没有“地面”的,所以我们要给imgView添加一个碰撞行为,并设置屏幕底部为碰撞边界来模拟落地撞击地面。

gif01.gif gif02.gif
#import "DynamicViewController.h"

@interface DynamicViewController ()<UICollisionBehaviorDelegate>
{
    UIImageView                 *_imgView;
    UIDynamicAnimator           *_dynamicAnimator;
    UIGravityBehavior           *_gravityBehavior;
    UICollisionBehavior         *_collisionBehavior;
    UIAttachmentBehavior        *_attachmentBehavior;
    UISnapBehavior              *_snapBehavior;
}
@end

@implementation DynamicViewController

- (void)viewDidLoad
{
    [super viewDidLoad];
    
    self.title = @"UIKit Dynamic";
    
    _imgView = [[UIImageView alloc] initWithFrame:CGRectMake(100, 100, 100, 100)];
    _imgView.image = [UIImage imageNamed:@"01.jpg"];
    _imgView.userInteractionEnabled = YES;
    UIPanGestureRecognizer *panGesture = [[UIPanGestureRecognizer alloc] initWithTarget:self action:@selector(panGestureHandle:)];
    [_imgView addGestureRecognizer:panGesture];
    [self.view addSubview:_imgView];
    
    
    _dynamicAnimator = [[UIDynamicAnimator alloc] initWithReferenceView:self.view];
    
    // 添加重力行为
    _gravityBehavior = [[UIGravityBehavior alloc] initWithItems:@[_imgView]];
    [_dynamicAnimator addBehavior:_gravityBehavior];
    
    // 添加碰撞行为
    _collisionBehavior = [[UICollisionBehavior alloc] initWithItems:@[_imgView]];
    _collisionBehavior.translatesReferenceBoundsIntoBoundary = YES; // 碰撞行为的边界
    [_dynamicAnimator addBehavior:_collisionBehavior];
    _collisionBehavior.collisionDelegate = self;
    
    //
    UITapGestureRecognizer *tapGesture = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(tapGestureHandle:)];
    [self.view addGestureRecognizer:tapGesture];
}

- (void)panGestureHandle:(UIPanGestureRecognizer *)panGesture
{
    CGPoint location = [panGesture locationInView:self.view];
    CGPoint boxLocation = [panGesture locationInView:_imgView];
    UIOffset centerOffet = UIOffsetMake(boxLocation.x-CGRectGetMidX(_imgView.bounds), boxLocation.y-CGRectGetMidY(_imgView.bounds));
    
    if(panGesture.state == UIGestureRecognizerStateBegan)
    {
        // 添加追随行为
        _attachmentBehavior = [[UIAttachmentBehavior alloc] initWithItem:_imgView offsetFromCenter:centerOffet attachedToAnchor:location];
        _attachmentBehavior.damping = 0.1;
        _attachmentBehavior.frequency = 0.4;
        [_dynamicAnimator addBehavior:_attachmentBehavior];
    }
    else if(panGesture.state == UIGestureRecognizerStateChanged)
    {
        [_attachmentBehavior setAnchorPoint:location];
    }
    else if(panGesture.state == UIGestureRecognizerStateEnded)
    {
        [_dynamicAnimator removeBehavior:_attachmentBehavior];
    }
}


// 吸附在手势点击的某点
- (void)tapGestureHandle:(UITapGestureRecognizer *)tapGesture
{
    CGPoint location = [tapGesture locationInView:self.view];
    
    if(_snapBehavior!=nil){
        [_dynamicAnimator removeBehavior:_snapBehavior];
    }
    
    // 添加吸附行为
    _snapBehavior = [[UISnapBehavior alloc] initWithItem:_imgView snapToPoint:location];
    _snapBehavior.damping = 0.1;
    [_dynamicAnimator addBehavior:_snapBehavior];
}


@end


UIKit动力学自定义

我们这里说的动力学自定义是指在系统基础上打包封装,而不是完全自定义,完全自定义是很复杂的。
比如,我们要实现动力项的“自由落体”,但内置的重力行为是无“地面”的,也就是说要自己在添加个“边界”来模拟地面,用碰撞行为来模拟“落地”。要完成一个完整的“自由落体”将要用到两种动力行为,我们可以将其封装为一个自定义的行为。
** 我们封装自己的类时,尽量和原有类保持风格一致。**

FreeFallBehavior.h

#import <UIKit/UIKit.h>

@interface FreeFallBehavior : UIDynamicBehavior


- (instancetype)initWithItems:(NSArray<id <UIDynamicItem>> *)items;


@end

FreeFallBehavior.m

#import "FreeFallBehavior.h"

@interface FreeFallBehavior ()

@end


@implementation FreeFallBehavior

- (instancetype)initWithItems:(NSArray<id <UIDynamicItem>> *)items
{
    if(self = [super init])
    {
        UIGravityBehavior *gravityBehavior = [[UIGravityBehavior alloc] initWithItems:items];
        [self addChildBehavior:gravityBehavior];
        
        UICollisionBehavior *collisionBehavior = [[UICollisionBehavior alloc] initWithItems:items];
        collisionBehavior.translatesReferenceBoundsIntoBoundary = YES;
        [self addChildBehavior:collisionBehavior];
    }
    
    return self;
}

@end
上一篇下一篇

猜你喜欢

热点阅读