iOS中UIDynamic物理仿真详解
本文中所有代码演示均有GitHub源码,点击下载
UIDynamic简介
简介:
- UIKit动力学最大的特点是将现实世界动力驱动的动画引入了UIKit,比如动力,铰链连接,碰撞,悬挂等效果,即将2D物理引擎引入了UIKit。
- 注意:UIKit动力学的引入,并不是为了替代CA或者UIView动画,在绝大多数情况下CA或者UIView动画仍然是最有方案,只有在需要引入逼真的交互设计的时候,才需要使用UIKit动力学它是作为现有交互设计和实现的一种补充。
其他2D仿真引擎:
- BOX2D:C语言框架,免费
- Chipmunk:C语言框架免费,其他版本收费
UIDynamic中的三个重要概念
Dynamic Animator:动画者,为动力学元素提供物理学相关的能力及动画,同时为这些元素提供相关的上下文,是动力学元素与底层iOS物理引擎之间的中介,将Behavior对象添加到Animator即可实现动力仿真。
Dynamic Animator Item:动力学元素,是任何遵守了UIDynamic协议的对象,从iOS7开始,UIView和UICollectionViewLayoutAttributes默认实现协议,如果自定义对象实现了该协议,即可通过Dynamic Animator实现物理仿真。
UIDynamicBehavior:仿真行为,是动力学行为的父类,基本的动力学行为类UIGravityBehavior、UICollisionBehavior、UIAttachmentBehavior、UISnapBehavior、UIPushbehavior以及UIDynamicItemBehavior均继承自该父类。
项目搭建演练
模拟重力体验物理仿真效果
要使用物理仿真,最基本的使用步骤是:
- 1> 要有一个 仿真者[UIDynamicAnimator] 用来仿真所有的物理行为
- 2> 要有物理 仿真行为[如重力UIGravity] 用来模拟重力的行为
- 3> 将物理仿真行为添加给仿真者实现仿真效果。
第一种情况——重力仿真
// 1. 谁来仿真?UIDynamicAnimator来负责仿真UIDynamicAnimator *animator = [[UIDynamicAnimator alloc] initWithReferenceView:self.view];// 2. 仿真个什么动作?自由落体UIGravityBehavior *gravity = [[UIGravityBehavior alloc] initWithItems:@[view, redView]];// 3. 开始仿真[animator addBehavior:gravity];
- 重力仿真效果图
01重力效果无边界检测.gif
第二种情况——增加边缘检测
默认情况下没有任何阻挡控件直接掉出屏幕,可以通过添加边缘检测行为防止掉出。
// 3. 碰撞检测 UICollisionBehavior *collision = [[UICollisionBehavior alloc] initWithItems:@[view, redView]]; // 设置不要出边界,碰到边界会被反弹 collision.translatesReferenceBoundsIntoBoundary = YES;// 4. 开始仿真 [animator addBehavior:collision];
- 增加边缘检测效果图
![](http://upload-images.jianshu.io/upload_images/1501122-b74f0e6f194e1c05.gif?imageMogr2/auto-orient/strip)
- 第三种情况——旋转
- 让控件旋转45°后,控件并不会倒下,因为控件的重心就在45°的那条线上。
- 如果修改为别的角度就会倒下
view.transform = CGAffineTransformMakeRotation(M_PI_4);
- 旋转效果图
![](http://upload-images.jianshu.io/upload_images/1501122-4e2381381d62a4b5.gif?imageMogr2/auto-orient/strip)
- 第四种情况——碰撞
- 再增加一个红色的控件的时候就会发生碰撞的效果。
- 碰撞效果图
项目框架搭建
一、结构分析
为了演示其他的几种行为效果,案例中需要用到
- UINavigationController[导航控制器],根控制器为列表控制器
- UITableViewController[列表控制器],用来展示所有的行为列表
- UIViewController[普通控制器],用来演示各种不同行为的效果
在显示各种行为的普通控制器中有2个共同点:
- 相同的背景效果
- 都有一个小方块
所以为了避免每个行为都要写一个控制器,然后写对应的背景及方块图片代码,就抽出一个示例控制器,用来显示所有的行为效果
- 只不过示例控制器要加载和显示的view,要根据要展示的行为去加载不同的view(多态的合理运用)
二、代码实现
1> 列表控制器
第一步加载显示导航控制器及列表控制器
- 通过属性列表或者数据源的方式加载所有的行为名词
_dynamicArr = @[@"吸附行为", @"推动行为", @"刚性附着行为", @"弹性附着行为", @"碰撞检测"];
- 通过给组尾设置一个空的view来隐藏多余行
self.tableView.tableFooterView = [[UIView alloc] init];
实现数据源方法显示出来
#pragma mark - 数据源方法// 几行- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {return _dynamicArr.count;}// 每行的具体内容- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {// 1. 设置可重用标识符static NSString *ID = @"cell";// 2. 根据可重用标识符去tableView 缓存区去取UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:ID];// 3. 设置每行cell 的文字cell.textLabel.text = _functions[indexPath.row];return cell; }
- 通过属性列表或者数据源的方式加载所有的行为名词
- 列表控制器效果图
![](http://upload-images.jianshu.io/upload_images/1501122-e78f29e2f1733469.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)
2> 跳转到演示控制器
- 实现代理方法,实现跳转
在跳转的时候将索引及cell的标题传过去
#pragma mark - 代理方法- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {// 1. 实例化一个仿真管理器WPFDemoController *demoVc = [[WPFDemoController alloc] init];// 2. 设置标题demoVc.title = _dynamicArr[indexPath.row];// 3. 传递功能类型demoVc.function = (int)indexPath.row;// 4. 跳转界面[self.navigationController pushViewController:demoVc animated:YES];}
3> 演示控制器根据索引去加载不同的view
- 做一个基本的view只用来设置背景及方块图片及仿真者,其他的view在此基础上添加功能,新建类 WPFBaseView
// 重写其initWithFrame 方法,设置基本信息
- (instancetype)initWithFrame:(CGRect)frame {if (self = [super initWithFrame:frame]) {// 以平铺的方式设置背景图片self.backgroundColor = [UIColor colorWithPatternImage:[UIImage imageNamed:@"BackgroundTile"]];// 设置方块UIImageView *boxView = [[UIImageView alloc] initWithImage:[UIImage imageNamed:@"Box1"]];boxView.center = CGPointMake(200, 220);[self addSubview:boxView];self.boxView = boxView;// 初始化仿真者UIDynamicAnimator *animator = [[UIDynamicAnimator alloc] initWithReferenceView:self];self.animator = animator;}return self;
}
- WPFDemoController:根据传入的索引去判断加载那个行为的view
// 在此之前要先在头文件中定义枚举类型
- (void)viewDidLoad {[super viewDidLoad];// 新建一个空的baseViewWPFBaseView *baseView = nil;// 根据不同的功能类型选择不同的视图// 运用了多态switch (self.function) {case kDemoFunctionSnap:baseView = [[WPFSnapView alloc] init];break;case kDemoFunctionPush:baseView = [[WPFPushView alloc] init];break;case kDemoFunctionAttachment:baseView = [[WPFAttachmentView alloc] init];break;case kDemoFunctionSpring:baseView = [[WPFSpringView alloc] init];break;case kDemoFunctionCollision:baseView = [[WPFCollisionView alloc] init];break;default:break;}baseView.frame = self.view.bounds;[self.view addSubview:baseView];}
- 加载不同view的效果
![](http://upload-images.jianshu.io/upload_images/1501122-c20fc53a5b47b47c.gif?imageMogr2/auto-orient/strip)
吸附行为:WPFSnapView
- UISnapBehavior吸附行为
- 在点击屏幕的时候获取触摸点
- 需要在创建吸附行为的时候指定要吸附的位置
- 创建好之后将吸附行为添加到仿真者上
- (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event {// 0. 触摸之前要清零之前的吸附事件,否则动作越来越小[self.animator removeAllBehaviors];// 1. 获取触摸对象UITouch *touch = [touches anyObject];// 2. 获取触摸点CGPoint loc = [touch locationInView:self];// 3 添加吸附事件UISnapBehavior *snap = [[UISnapBehavior alloc] initWithItem:self.boxView snapToPoint:loc];// 改变震动幅度,0表示振幅最大,1振幅最小snap.damping = 0.5;// 4. 将吸附事件添加到仿真者行为中[self.animator addBehavior:snap];
}
- 吸附行为效果图
![](http://upload-images.jianshu.io/upload_images/1501122-f17a691e1a2e823c.gif?imageMogr2/auto-orient/strip)
推动行为:WPFPushView
- UIPushBehavior推动行为
介绍
- 推行为可以为一个视图施加一个作用力,该力可以是持续的,也可以是一次性的
可以设置力的大小,方向和作用点等信息
属性:
- mode: 推动类型(一次性推动或是持续推送)
- active: 是否激活,如果是一次性推动,需要激活
- angle: 推动角度
- 推动力量
实例化推行为
通过拖拽手势获取起始点及其他状态的点
设置全局变量
@interface WPFPushView ()
{UIImageView *_smallView; // 显示在第一个触摸点位置的图片框UIPushBehavior *_push; // 推动的行为CGPoint _firstPoint; // 手指点击的第一个点CGPoint _currentPoint; // 当前触摸点
}
@end
- 推行为的创建
// 重写init 方法
- (instancetype)init {if (self = [super init]) {// 1. 添加蓝色viewUIView *blueView = [[UIView alloc] initWithFrame:CGRectMake(150, 300, 20, 20)];blueView.backgroundColor = [UIColor blueColor];[self addSubview:blueView];// 2. 添加图片框,拖拽起点UIImageView *smallView = [[UIImageView alloc] initWithImage:[UIImage imageNamed:@"AttachmentPoint_Mask"]];// 该图片框默认是隐藏的,在触摸屏幕的时候再显示出来smallView.hidden = YES;[self addSubview:smallView];// 建立全局关系_smallView = smallView;// 3. 添加推动行为UIPushBehavior *push = [[UIPushBehavior alloc] initWithItems:@[self.boxView] mode:UIPushBehaviorModeInstantaneous];[self.animator addBehavior:push];_push = push;// 4. 增加碰撞检测UICollisionBehavior *collision = [[UICollisionBehavior alloc] initWithItems:@[blueView, self.boxView]];collision.translatesReferenceBoundsIntoBoundary = YES;[self.animator addBehavior:collision];// 5. 添加拖拽手势UIPanGestureRecognizer *pan = [[UIPanGestureRecognizer alloc] initWithTarget:self action:@selector(panAction:)];[self addGestureRecognizer:pan];}return self;
}
- 通过拖拽手势根据不同状态去确定力的方向和大小
// 监听开始拖拽的方法
- (void)panAction:(UIPanGestureRecognizer *)pan {// 如果是刚开始拖拽,则设置起点处的小圆球if (pan.state == UIGestureRecognizerStateBegan) {_firstPoint = [pan locationInView:self];_smallView.center = _firstPoint;_smallView.hidden = NO;// 如果当前拖拽行为正在移动} else if (pan.state == UIGestureRecognizerStateChanged) {_currentPoint = [pan locationInView:self];// 重绘当前页面[self setNeedsDisplay];// 如果当前拖拽行为结束} else if (pan.state == UIGestureRecognizerStateEnded){// 1. 计算偏移量CGPoint offset = CGPointMake(_currentPoint.x - _firstPoint.x, _currentPoint.y - _firstPoint.y);// 2. 计算角度CGFloat angle = atan(offset.y / offset.x);if (_currentPoint.x > _firstPoint.x) {angle = angle - M_PI;}_push.angle = angle;// 3. 计算距离CGFloat distance = hypot(offset.y, offset.x);// 4. 设置推动的力度,与线的长度成正比_push.magnitude = directtion / 10;// 5. 使单次推行为有效_push.active = YES;// 6. 将拖拽的线隐藏_firstPoint = CGPointZero;_currentPoint = CGPointZero;// 7. 将起点的小圆隐藏_smallView.hidden = YES;// 8. 进行重绘[self setNeedsDisplay];}
}
- 设置划线操作
- (void)drawRect:(CGRect)rect {// 1. 开启上下文对象CGContextRef ref = UIGraphicsGetCurrentContext();// 2. 获取路径对象UIBezierPath *path = [UIBezierPath bezierPath];// 3. 划线[path moveToPoint:_firstPoint];[path addLineToPoint:_currentPoint];CGContextAddPath(ref, path.CGPath);// 4. 设置线宽path.lineWidth = 7;// 5. 线的颜色[[UIColor greenColor] setStroke];// 6. 渲染[path stroke];}
- 推行为效果图
![](http://upload-images.jianshu.io/upload_images/1501122-27b80d9a3e789553.gif?imageMogr2/auto-orient/strip)
刚性附着行为:WPFAttachmentView
简介:
- 附着行为是描述一个视图与一个锚点或者另一个视图相连接的情况
- 附着行为描述的是两点之间的连接情况,可以模拟刚性或者弹性连接
- 在多个物理键设定多个UIAttachment,可以模拟多物体连接。
属性
- attachedBehaviorType: 连接类型(连接到锚点或视图)
- items: 连接到视图数组
- anchorPoint: 连接锚点
- length: 距离连接锚点的距离
注意: 只要设置了以下两个属性,即为弹性连接
- damping: 振幅大小
frequency: 震动频率
设置全局变量
@interface WPFPushView ()
{// 附着点图片框UIImageView *_anchorImgView;// 参考点图片框(boxView 内部)UIImageView *_offsetImgView;
}
@end
- 创建附着行为
- (instancetype)init {if (self = [super init]) {// 1. 设置boxView 的中心点self.boxView.center = CGPointMake(200, 200);// 2. 添加附着点CGPoint anchorPoint = CGPointMake(200, 100);UIOffset offset = UIOffsetMake(20, 20);// 3. 添加附着行为UIAttachmentBehavior *attachment = [[UIAttachmentBehavior alloc] initWithItem:self.boxView offsetFromCenter:offset attachedToAnchor:anchorPoint];[self.animator addBehavior:attachment];self.attachment = attachment;// 4. 设置附着点图片(即直杆与被拖拽图片的连接点)UIImage *image = [UIImage imageNamed:@"AttachmentPoint_Mask"];UIImageView *anchorImgView = [[UIImageView alloc] initWithImage:image];anchorImgView.center = anchorPoint;[self addSubview:anchorImgView];_anchorImgView = anchorImgView;// 3. 设置参考点_offsetImgView = [[UIImageView alloc] initWithImage:image];CGFloat x = self.boxView.bounds.size.width * 0.5 + offset.horizontal;CGFloat y = self.boxView.bounds.size.height * 0.5 + offset.vertical;_offsetImgView.center = CGPointMake(x, y);[self.boxView addSubview:_offsetImgView];// 4. 增加拖拽手势UIPanGestureRecognizer *pan = [[UIPanGestureRecognizer alloc] initWithTarget:self action:@selector(panAction:)];[self addGestureRecognizer:pan];}return self;
}
- 添加拖拽手势,在拖拽手势移动的时候根据附着点及其轴点去绘制线段
- 通过两个属性保存附着点,及轴点
// 拖拽的时候会调用的方法
- (void)panAction:(UIPanGestureRecognizer *)pan {// 1. 获取触摸点CGPoint loc = [pan locationInView:self];// 2. 修改附着行为的附着点_anchorImgView.center = loc;self.attachment.anchorPoint = loc;// 3. 进行重绘[self setNeedsDisplay];}
- 在绘制的时候需要注意将图片框的轴点进行坐标转换
- (void)drawRect:(CGRect)rect {// 1.获取图形上下文CGContextRef context = UIGraphicsGetCurrentContext();// 2.设置路径起点CGContextMoveToPoint(context, _anchorImage.center.x, _anchorImage.center.y);// 2.2设置路径画线的点,注意需要将轴点的坐标进行转换// 使得两个点的坐标位于同一个坐标系下// addline// 去偏移点相对于父视图的坐标CGPoint p = [self convertPoint:_offsetImage.center fromView:self.box];CGContextAddLineToPoint(context, p.x, p.y);// 2.3设置虚线样式CGFloat lengths[] = {10.0f, 8.0f};CGContextSetLineDash(context, 0.0, lengths, 2);// 2.4设置线宽CGContextSetLineWidth(context, 5.0f);// 3.渲染,绘制路径CGContextDrawPath(context, kCGPathStroke);
}
- 刚性附着行为效果图
- 中心点没有偏移
![](http://upload-images.jianshu.io/upload_images/1501122-ee9fd1ff8aca5fcf.gif?imageMogr2/auto-orient/strip)
* 中心点偏移</br>
![](http://upload-images.jianshu.io/upload_images/1501122-30aa0230143bc83b.gif?imageMogr2/auto-orient/strip)
弹性附着行为:WPFSpringView
弹性附着行为与刚性附着行为类似,只需要设置两个属性就好了。
// 振幅 self.attachment.damping = 0.1f; // 频率 self.attachment.frequency = 1.0f;
弹性附着行为的view只需要继承刚性附着行为就可以了。
// WPFAttachView是刚性附着行为的view,WPFSpringView为弹性附着行为的view @interface WPFSpringView : WPFAttachView
- 但是需要在后面需要修改弹性附着行为的效果,所以要将刚性附着行为内部的附着行为暴露在.h文件中
@property (nonatomic, weak) UIAttachmentBehavior *attachment;
- 1.只设置了振幅和频率的效果
// 振幅 self.attachment.damping = 0.1f; // 频率 self.attachment.frequency = 1.0f;
![](http://upload-images.jianshu.io/upload_images/1501122-19134596c4644182.gif?imageMogr2/auto-orient/strip)
2.通过KVO监听方块的中心点的变化,实时去更新绘图后的效果
// KVO监听boxcenter的改变 [self.box addObserver:self forKeyPath:@"center" options:NSKeyValueObservingOptionNew context:nil];
- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary<NSString *,id> *)change context:(void *)context {[self setNeedsDisplay];}
![](http://upload-images.jianshu.io/upload_images/1501122-dda8ebb6ede0ec1d.gif?imageMogr2/auto-orient/strip)
- 3.增加了重力后的效果
// 添加重力 UIGravityBehavior *gravity = [[UIGravityBehavior alloc] initWithItems:@[self.box]]; [self.animator addBehavior:gravity];
![](http://upload-images.jianshu.io/upload_images/1501122-3f9ea51fed81c4a3.gif?imageMogr2/auto-orient/strip)
![](http://upload-images.jianshu.io/upload_images/1501122-b40dccb69260ddad.gif?imageMogr2/auto-orient/strip)
- 4.添加了碰撞检测后的效果
// 添加碰撞检测 UICollisionBehavior *collision = [[UICollisionBehavior alloc] initWithItems:@[self.box]]; collision.translatesReferenceBoundsIntoBoundary = YES; [self.animator addBehavior:collision];
![](http://upload-images.jianshu.io/upload_images/1501122-0b900f0a8a6a954a.gif?imageMogr2/auto-orient/strip)
碰撞检测
- 在碰撞界面添加一个红色的view
- 1.红色的view也添加到碰撞检测行为中
// 增加一个红色的条状view UIView *redV = [[UIView alloc] initWithFrame:CGRectMake(0, 400, 180, 30)]; redV.backgroundColor = [UIColor redColor]; [self addSubview:redV];
![](http://upload-images.jianshu.io/upload_images/1501122-0f7983da2ef308a7.gif?imageMogr2/auto-orient/strip)
- 2.红色view不添加到任何行为中
![](http://upload-images.jianshu.io/upload_images/1501122-837542911602b7e1.gif?imageMogr2/auto-orient/strip)
- 3.如果只想在碰到红色view的时候方块掉下去,红色view不动,需要给碰撞检测增减一条碰撞边界
#pragma mark - 在红色view的上方添加一个边界到边界检测行为中 // 添加一个边界,起点,终点作为一条直线。 CGPoint fromP = CGPointMake(0, 400); CGPoint toP = CGPointMake(180, 400); [collision addBoundaryWithIdentifier:@"line" fromPoint:fromP toPoint:toP];
![](http://upload-images.jianshu.io/upload_images/1501122-824bf9225cb6c351.gif?imageMogr2/auto-orient/strip)
- 4.也可以增加一个路径
注意:在增加路径的时候碰撞会碰在弧线两个顶点的连线的位置上,可以通过填充的模式看的更清楚一些。
// 添加路径
UIBezierPath *path = [UIBezierPath bezierPathWithArcCenter:CGPointMake(200, 300) radius:100 startAngle:M_PI_2 endAngle:M_PI clockwise:YES];
[collision addBoundaryWithIdentifier:@"bcd" forPath:path];
![](http://upload-images.jianshu.io/upload_images/1501122-aba950012f4cb94f.gif?imageMogr2/auto-orient/strip)
5.补充
- 各种碰撞行为都有一个action的block,可以通过这个block监听在碰撞行为过程中的动态信息。
collision.action = ^(){ NSLog(@"%@", NSStringFromCGRect(self.box.frame)); };
可以设置边缘检测的代理,根据identifer标记去区分碰撞到哪一个边界了。
// 设置代理 collision.collisionDelegate = self;#pragma mark - UICollisionBehaviorDelegate- (void)collisionBehavior:(UICollisionBehavior*)behavior beganContactForItem:(id <UIDynamicItem>)item withBoundaryIdentifier:(nullable id <NSCopying>)identifier atPoint:(CGPoint)p {NSLog(@"%@", identifier); }
- 各种碰撞行为都有一个action的block,可以通过这个block监听在碰撞行为过程中的动态信息。
多视图附加行为
- 1> 创建视图
- 2> 添加视图之间的附着行为
- 3> 添加重力行为
- 4> 添加边缘检测行为
- 5> 添加拖拽手势,单独处理头部视图的附着行为。
- 在开始拖拽式,实例化拖拽行为。设置附着点为触摸点
- 在拖动过程中,实时修改附着点为触摸点
- 在拖动结束后,移除附着行为,否则不能正常使用。
- 效果图
- 重力在下
![](http://upload-images.jianshu.io/upload_images/1501122-d4fc6739dce04c53.gif?imageMogr2/auto-orient/strip)
* 重力在上</br>
![](http://upload-images.jianshu.io/upload_images/1501122-da3ac81a155ccdf4.gif?imageMogr2/auto-orient/strip)
- 重力的方向可以通过
@property (readwrite, nonatomic) CGVector gravityDirection;去设置- 根据x,y值的几何方向去确定重力的方向。
界面效果:
- 有9个圆形的球,一个比较大的作为头部。
- 在从屏幕任意位置拖动的时候所有的圆球都成一条串的效果,沿着重力方向下垂。
- 抬起手指后,自由坠落。
1.创建9个view,并设置圆角半径作为圆形,将最后一个修改为更大的效果。
// 添加9个子控件CGFloat startX = 20;CGFloat startY = 100;CGFloat r = 10;NSMutableArray *arrM = [NSMutableArray arrayWithCapacity:9];for (int i = 0; i < 9; i++) {CGFloat x = startX + 2 * r * i;CGFloat y = startY;CGFloat width = 2 * r;CGFloat heigth = width;UIView *v = [[UIView alloc] initWithFrame:CGRectMake(x, y, width, heigth)];v.backgroundColor = [UIColor colorWithRed:arc4random_uniform(256)/255.0 green:arc4random_uniform(256)/255.0 blue:arc4random_uniform(256)/255.0 alpha:1.0];v.layer.cornerRadius = r;if (i == 8) {r = 20;v.backgroundColor = [UIColor greenColor];v.frame = CGRectMake(v.frame.origin.x, v.frame.origin.y - 10, 2 * r, 2 * r);v.layer.cornerRadius = r;}[self.view addSubview:v];// 保存到集合中[arrM addObject:v];}
- 9个圆球效果图
![](http://upload-images.jianshu.io/upload_images/1501122-096f0b049b96538b.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)
- 遍历集合中所有的元素并添加附加行为
- 最后一个要留着,单独处理
// 添加吸附吸附行为 for (int i = 0; i < 8; i++) {UIAttachmentBehavior *attachment = [[UIAttachmentBehavior alloc] initWithItem:arrM[i] attachedToItem:arrM[i+1]];[_animator addBehavior:attachment]; }
- 最后一个要留着,单独处理
- 给所有的元素添加重力行为
// 重力仿真 UIGravityBehavior *gravity = [[UIGravityBehavior alloc] initWithItems:arrM]; // 指定重力的方向 gravity.gravityDirection = CGVectorMake(0.0, 1.0); [_animator addBehavior:gravity];
- 添加边缘检测行为
// 边缘检测 UICollisionBehavior *collision = [[UICollisionBehavior alloc] initWithItems:arrM]; collision.translatesReferenceBoundsIntoBoundary = YES; [_animator addBehavior:collision];
添加拖拽手势,在拖拽手势内部根据状态进行处理
- 在开始拖拽的时候,给头部的view实例化附着行为,附着点就是触摸点。
- 在拖拽过程中,附加行为的附着点仍是触摸点。
在拖拽结束后,将附着行为从仿真者中移除。
CGPoint loc = [pan locationInView:self.view];if (UIGestureRecognizerStateBegan == pan.state) {// 开始拖拽,实例化附加行为_attachment = [[UIAttachmentBehavior alloc] initWithItem:_headView attachedToAnchor:loc];[_animator addBehavior:_attachment];} else if (UIGestureRecognizerStateChanged == pan.state) {// 拖拽过程中_attachment.anchorPoint = loc;} else if (UIGestureRecognizerStateEnded == pan.state){// 结束拖拽[_animator removeBehavior:_attachment];}
iOS中UIDynamic物理仿真详解相关推荐
- iOS中MVC等设计模式详解
iOS中MVC等设计模式详解 在iOS编程,利用设计模式可以大大提高你的开发效率,虽然在编写代码之初你需要花费较大时间把各种业务逻辑封装起来.(事实证明这是值得的!) 模型-视图-控制器(MVC)设计 ...
- iOS中 CoreGraphics快速绘图(详解) 韩俊强的博客
第一步:先科普一下基础知识: Core Graphics是基于C的API,可以用于一切绘图操作 Core Graphics 和Quartz 2D的区别 quartz是一个通用的术语,用于描述在IOS和 ...
- iOS中UINavigationController控制器使用详解
一.概述 UINavigationController用来管理视图控制器,在多视图控制器中常用.它以栈的形式管理视图控制器,管理视图控制器个数理论上不受限制(实际受内存限制),push和pop方法来弹 ...
- iOS 中的编码方式详解(主要讲解Unicode)
当你在处理文本时,如果你不是在写一些非常古老的代码(legacy code),那么你一定要使用 Unicode.幸运的是,苹果和 NeXT 一直致力于推动 Unicode 标准的建立,而 NeXT 在 ...
- IOS中UIActionSheet使用方法详解
一.初始化方法 - (instancetype)initWithTitle:(NSString *)title delegate:(id<UIActionSheetDelegate>)de ...
- ios首次加载web_IOS_IOS中UIWebView的使用详解,一、初始化与三种加载方式
UI - phpStudy...
IOS中UIWebView的使用详解 一.初始化与三种加载方式 UIWebView继承与UIView,因此,其初始化方法和一般的view一样,通过alloc和init进行初始化,其加载数据的方式有三种 ...
- VMware虚拟机文件夹中各文件作用详解
VMware虚拟机文件夹中各文件作用详解 虚拟机的文件管理由VMware Workstation来执行. 一个虚拟机一般以一系列文件的形式储存在宿主机中, 这些文件一般在由workstation为虚拟 ...
- iOS 证书与签名 解惑详解
iOS 证书与签名 解惑详解 分类: iPhone2012-06-06 19:57 9426人阅读 评论(1) 收藏 举报 iosxcodecryptographyappleiphone测试 目录(? ...
- ncverilog脚本_NC-Verilog仿真详解
ncverilog仿真详解 发表在ASIC/FPGA/汇编, 学习笔记, 编程开发 | 由阿布 | 十一月26, 2011 | 0标签: ncverilog, 仿真 数位IC工具简介--Simulat ...
最新文章
- SQL查询语句 select 详解
- CSS3蓝色宽屏二级下拉菜单DEMO演示
- 【Android 插件化】DroidPlugin 编译运行 ( DroidPlugin 简介 | 编译 DroidPlugin 官方示例 | 运行 DroidPlugin 官方示例 )
- JVM堆新生代分配比例
- 笔记-信息化与系统集成技术-供应链管理
- 视觉slam发展史--从开始到未来
- 计算机设备的存放,计算机硬件储存设备与网络储存的发展现状
- linux发行版_7款颜值当道的Linux发行版操作系统
- 云的种类 计算机,云架构常用的云组件类型分析
- 交叉火力dsp手机调音软件_汽车音响DSP调音软件哪个好?8音度优美声喜力士常见车载DSP调音软件下载...
- 计算机画cad很慢怎么办,【2人回答】画CAD图时电脑很卡怎么办?-3D溜溜网
- 韦根协议c语言,哪为高手懂韦根协议啊。怎么用单片机来读取韦根26的ID卡的信息,以下为我写的程序,ID...
- Android本地音乐播放器
- java 排班日历,排班日历
- 【转】Rstudio中修改工作路径的三种方法
- 怎么把柱形图和折线图放在一起_Excel图表制作:柱形图和折线图的组合图案例...
- oracle audit_actions,Oracle Audit 功能的使用和说明
- MTK DDR进行ETT之后的压力---测试环境的搭建
- swagger在VS2019 .net core2.2中的使用,及报错undefined /swagger/v1/swagger.json的解决办法
- Step1:模型 16个相机参数(内参、外参、畸变参数)