UIDynamicAnimator物理动画效果

本文介绍了一种通过手势操作使视图以自然的方式抛掷出屏幕的技术实现方法。利用Swift编程语言和UIKit框架中的物理动画特性,文章详细展示了如何通过拖拽手势触发视图的抛掷动作,并结合旋转等效果增强视觉体验。

//如何用手势很自然的将 view抛掷出屏幕。

#define WIDTH [[UIScreen mainScreen] bounds].size.width

#define HEIGHT [[UIScreen mainScreen] bounds].size.height


static constCGFloat ThrowingThreshold = 1000;

static constCGFloat ThrowingVelocityPadding = 35;


@interface ViewController ()


@property (nonatomic,strong)UIImageView *imageView;

//拖动点的初始位置

@property (nonatomic,strong)UIView *blueView;

//拖动点的最终位置

@property (nonatomic,strong)UIView *redView;

//初始bounds

@property (nonatomic,assign)CGRect originalBounds;

//初始center

@property (nonatomic,assign)CGPoint originalCenter;


//UIDynamicAnimator UIKit中的一个引擎,用于支持最基本的物理动画效果

@property (nonatomic)UIDynamicAnimator *animator;

@property (nonatomic)UIAttachmentBehavior *attachmentBehavior;

@property (nonatomic)UIPushBehavior *pushBehavior;

@property (nonatomic)UIDynamicItemBehavior *itemBehavior;


@end


@implementation ViewController


- (void)viewDidLoad {

    [superviewDidLoad];

    [self initWithImageView];

    [self.view addGestureRecognizer:[[UIPanGestureRecognizeralloc]initWithTarget:selfaction:@selector(handleAttachmentGesture:)]];

    //参照 self.view定义了 animator的坐标系。

    self.animator = [[UIDynamicAnimator alloc]initWithReferenceView:self.view];

    self.originalBoundsself.imageView.bounds;

    self.originalCenterself.imageView.center;

}


- (void)initWithImageView{

    self.imageView = [[UIImageView alloc]initWithImage:[UIImageimageNamed:@"goldfish_feature.jpg"]];

    self.imageView.frameCGRectMake(50,HEIGHT / 4,WIDTH -100,HEIGHT /3);

    self.imageView.userInteractionEnabled = YES;

    [self.view addSubview:self.imageView];

    

    //添加绿色指示点

    self.blueView = [[UIView alloc]initWithFrame:CGRectMake(100,HEIGHT / 4 *3 +50,20,20)];

    self.blueView.backgroundColor = [UIColor blueColor];

    [self.view addSubview:self.blueView];

    //添加红色指示点

    self.redView = [[UIView alloc]initWithFrame:CGRectMake(150,HEIGHT / 2 , 20,20)];

    self.redView.backgroundColor = [UIColor redColor];

    [self.view addSubview:self.redView];

    

}



- (void)handleAttachmentGesture:(UIPanGestureRecognizer *)pan{

    CGPoint location = [pan locationInView:self.view];

    CGPoint boxLocation = [pan locationInView:self.imageView];

    

    switch (pan.state) {

        case UIGestureRecognizerStateBegan:

        {

            NSLog(@"you touch started postion %@",NSStringFromCGPoint(location));

            NSLog(@"location in imageView started is%@",NSStringFromCGPoint(boxLocation));

            //移除animator中所有已有的行为

            [self.animator removeAllBehaviors];

            //创建一个UIAttachmentBehavior,将用户tap imageView上的点连接到一个锚点,随后,对锚点的改变,会引发imageView的移动

            UIOffset centerOffset =UIOffsetMake(boxLocation.x -CGRectGetMidX(self.imageView.bounds), location.y - CGRectGetMidY(self.imageView.bounds));

            

           //将锚点连接到一个 view上,就像安装了一个无形的拉杆:将锚点连接到 view中固定的位置上。

           //  更新红色正方形,表示出锚点,而蓝色正方形则表示连接到 imageView内部的点 (现在他们都是一样的)

           // 将这个行为添加到 animator中,使其具有效果。

            self.attachmentBehavior =[[UIAttachmentBehavior alloc]initWithItem:self.imageView offsetFromCenter:centerOffset attachedToAnchor:location];

            

            self.redView.center = self.attachmentBehavior.anchorPoint;

            self.blueView.center = location;

            //animator添加一个行为

            [self.animator addBehavior:self.attachmentBehavior];

        }

            break;

        case UIGestureRecognizerStateEnded:{

            //移除animator上所有的 attachmentBehavior

            [self.animator removeBehavior:self.attachmentBehavior];

            //1 获得手势的拖拽速度。

            CGPoint velocity = [pan velocityInView:self.view];

            //利用速度和勾股定理 (Pythagorean theorem),计算出速度的幅度 - 也就是由 x方向上的速度和 y方向上的速度构成的三角形斜边。

            CGFloat magnitude = sqrtf((velocity.x * velocity.x) + (velocity.y * velocity.y));

            

            if (magnitude >ThrowingThreshold) {

                //2 假设手势的幅度超过了最低阀值,那么就配置一个 push behavior

                //push behavior可以是持续性的,或者瞬间的应用到某个对象中。这里,我们需要给 imageView一个瞬间的 push行为。

               

                UIPushBehavior *pushBehavior = [[UIPushBehavioralloc]

                                                initWithItems:@[self.imageView]

                                                mode:UIPushBehaviorModeInstantaneous];

                 //我们希望 imageView的移动方向是由 x y轴上的速度转换为一个矢量决定的。最后,将 push行为添加到 animator上。

                pushBehavior.pushDirection =CGVectorMake((velocity.x /10) , (velocity.y /10));

                pushBehavior.magnitude = magnitude / ThrowingVelocityPadding;

                self.pushBehavior = pushBehavior;

                [self.animatoraddBehavior:self.pushBehavior];

                //3在这里给 imageView添加一些旋转效果,让图片飞离屏幕。这里有复杂的数学知识介绍。

               //其中的一些效果取决于发起手势操作的手指与边缘的距离。

               //在此处,设置不同的值,观察它们移动的效果,然后使用最好的那个值即可。

                NSInteger angle = arc4random_uniform(30) -10;

                self.itemBehavior =                [[UIDynamicItemBehavioralloc]initWithItems:@[self.imageView]];

                self.itemBehavior.friction =0.2;//摩擦力

                self.itemBehavior.allowsRotation =YES;

                [self.itemBehavior addAngularVelocity: angle forItemself.imageView];

                [self.animator addBehavior:self.itemBehavior];

                //4 指定时间间隔之后,以动画的形式将 imageView还原到最初状态。

                                      [self performSelector:@selector(resetDemo) withObject:nil afterDelay:0.5];

            }

            else {

                [selfresetDemo];

            }

        }

        default:

            [self.attachmentBehavior setAnchorPoint:[panlocationInView:self.view]];

            self.redView.center = self.attachmentBehavior.anchorPoint;

            break;

    }

}

//完成拖拽后将imageView还原到原来的位置

- (void)resetDemo

{

    [self.animator removeAllBehaviors];

    //重置时的动画

    [UIView animateWithDuration:0.8 animations:^{

        self.imageView.bounds =self.originalBounds;

        self.imageView.center =self.originalCenter;

        self.imageView.transform = CGAffineTransformIdentity;

    }];

}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值