//如何用手势很自然的将 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.originalBounds = self.imageView.bounds;
self.originalCenter = self.imageView.center;
}
- (void)initWithImageView{
self.imageView = [[UIImageView alloc]initWithImage:[UIImageimageNamed:@"goldfish_feature.jpg"]];
self.imageView.frame = CGRectMake(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 forItem: self.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;
}];
}