zoukankan      html  css  js  c++  java
  • IOS-UIDynamic

      1 //
      2 //  ViewController.m
      3 //  IOS_0306_UIDynamic
      4 //
      5 //  Created by ma c on 16/3/6.
      6 //  Copyright © 2016年 博文科技. All rights reserved.
      7 //
      8 
      9 #import "ViewController.h"
     10 
     11 @interface ViewController ()
     12 
     13 @property (weak, nonatomic) IBOutlet UIView *redView;
     14 ///物理仿真器
     15 @property (nonatomic, strong) UIDynamicAnimator *dynamic;
     16 
     17 
     18 @end
     19 
     20 @implementation ViewController
     21 
     22 /*
     23  一、简介
     24  1.什么是UIDynamic
     25  UIDynamic是从iOS 7开始引入的一种新技术,隶属于UIKit框架
     26  可以认为是一种物理引擎,能模拟和仿真现实生活中的物理现象
     27  重力、弹性碰撞等现象
     28  
     29  2.物理引擎的价值
     30  广泛用于游戏开发,经典成功案例是“愤怒的小鸟”
     31  让开发人员可以在远离物理学公式的情况下,实现炫酷的物理仿真效果
     32  提高了游戏开发效率,产生更多优秀好玩的物理仿真游戏
     33  
     34  3.知名的2D物理引擎
     35  Box2d
     36  Chipmunk
     37  
     38  
     39  二、使用步骤
     40  要想使用UIDynamic来实现物理仿真效果,大致的步骤如下
     41  1.创建一个物理仿真器(顺便设置仿真范围)
     42  
     43  2.创建相应的物理仿真行为(顺便添加物理仿真元素)
     44  
     45  3.将物理仿真行为添加到物理仿真器中  开始仿真
     46 
     47  
     48  三、三大概念
     49  1.物理仿真元素(Dynamic Item)
     50  谁要进行物理仿真?
     51  
     52  2.物理仿真行为(Dynamic Behavior)
     53  执行怎样的物理仿真效果?怎样的动画效果?
     54  
     55  3.物理仿真器(Dynamic Animator)
     56  让物理仿真元素执行具体的物理仿真行为
     57 
     58  
     59  四、物理仿真元素
     60  1.注意
     61  不是任何对象都能做物理仿真元素
     62  不是任何对象都能进行物理仿真
     63  
     64  2.哪些对象才能做物理仿真元素
     65  任何遵守了UIDynamicItem协议的对象
     66  UIView默认已经遵守了UIDynamicItem协议,因此任何UI控件都能做物理仿真
     67  UICollectionViewLayoutAttributes类默认也遵守UIDynamicItem协议
     68  
     69  
     70 五、物理仿真行为
     71  1.UIDynamic提供了以下几种物理仿真行为
     72  UIGravityBehavior:重力行为
     73  UICollisionBehavior:碰撞行为
     74  UISnapBehavior:捕捉行为
     75  UIPushBehavior:推动行为
     76  UIAttachmentBehavior:附着行为
     77  UIDynamicItemBehavior:动力元素行为
     78  
     79  2.物理仿真行为须知
     80  上述所有物理仿真行为都继承自UIDynamicBehavior
     81  所有的UIDynamicBehavior都可以独立进行
     82  组合使用多种行为时,可以实现一些比较复杂的效果
     83  
     84 
     85  六、物理仿真器
     86  1.物理仿真器须知
     87  它可以让物理仿真元素执行物理仿真行为
     88  它是UIDynamicAnimator类型的对象
     89  
     90  2.UIDynamicAnimator的初始化
     91  - (instancetype)initWithReferenceView:(UIView *)view;
     92  view参数:是一个参照视图,表示物理仿真的范围
     93 
     94  3.UIDynamicAnimator的常见方法
     95  - (void)addBehavior:(UIDynamicBehavior *)behavior;
     96  添加1个物理仿真行为
     97  
     98  - (void)removeBehavior:(UIDynamicBehavior *)behavior;
     99  移除1个物理仿真行为
    100  
    101  - (void)removeAllBehaviors;
    102  移除之前添加过的所有物理仿真行为
    103  
    104  4.UIDynamicAnimator的常见属性
    105  @property (nonatomic, readonly) UIView* referenceView;
    106  参照视图
    107  
    108  @property (nonatomic, readonly, copy) NSArray* behaviors;
    109  添加到物理仿真器中的所有物理仿真行为
    110  
    111  @property (nonatomic, readonly, getter = isRunning) BOOL running;
    112  是否正在进行物理仿真
    113  
    114  @property (nonatomic, assign) id <UIDynamicAnimatorDelegate> delegate;
    115  代理对象(能监听物理仿真器的仿真过程,比如开始和结束)
    116  
    117  
    118  七.重力行为(UIGravityAnimator)
    119  1.简介
    120  给定重力方向、加速度,让物体朝着重力方向掉落
    121  
    122  2.UIGravityBehavior的初始化
    123  - (instancetype)initWithItems:(NSArray *)items;
    124  item参数 :里面存放着物理仿真元素
    125  
    126  3.UIGravityBehavior常见方法
    127  - (void)addItem:(id <UIDynamicItem>)item;
    128  添加1个物理仿真元素
    129  
    130  - (void)removeItem:(id <UIDynamicItem>)item;
    131  移除1个物理仿真元素
    132 
    133  4.UIGravityBehavior常见属性
    134  @property (nonatomic, readonly, copy) NSArray* items;
    135  添加到重力行为中的所有物理仿真元素
    136  
    137  @property (readwrite, nonatomic) CGVector gravityDirection;
    138  重力方向(是一个二维向量)
    139  
    140  @property (readwrite, nonatomic) CGFloat angle;
    141  重力方向(是一个角度,以x轴正方向为0°,顺时针正数,逆时针负数)
    142  
    143  @property (readwrite, nonatomic) CGFloat magnitude;
    144  量级(用来控制加速度,1.0代表加速度是1000 points /second²)
    145 
    146  
    147  八、碰撞行为(UICollisionBehavior)
    148  1.简介
    149  可以让物体之间实现碰撞效果
    150  可以通过添加边界(boundary),让物理碰撞局限在某个空间中
    151  
    152  2.UICollisionBehavior边界相关的方法
    153  - (void)addBoundaryWithIdentifier:(id <NSCopying>)identifier forPath:(UIBezierPath*)bezierPath;
    154  - (void)addBoundaryWithIdentifier:(id <NSCopying>)identifier fromPoint:(CGPoint)p1 toPoint:(CGPoint)p2;
    155  - (UIBezierPath*)boundaryWithIdentifier:(id <NSCopying>)identifier;
    156  - (void)removeBoundaryWithIdentifier:(id <NSCopying>)identifier;
    157  @property (nonatomic, readonly, copy) NSArray* boundaryIdentifiers;
    158  - (void)removeAllBoundaries;
    159 
    160  3.UICollisionBehavior常见用法
    161  @property (nonatomic, readwrite) BOOL translatesReferenceBoundsIntoBoundary;
    162  是否以参照视图的bounds为边界
    163  
    164  - (void)setTranslatesReferenceBoundsIntoBoundaryWithInsets:(UIEdgeInsets)insets;
    165  设置参照视图的bounds为边界,并且设置内边距
    166  
    167  @property (nonatomic, readwrite) UICollisionBehaviorMode collisionMode;
    168  碰撞模式(分为3种,元素碰撞、边界碰撞、全体碰撞)
    169  
    170  @property (nonatomic, assign, readwrite) id <UICollisionBehaviorDelegate> collisionDelegate;
    171  代理对象(可以监听元素的碰撞过程)
    172  
    173  九.捕捉行为(UISnapBehavior)
    174  1.简介
    175  可以让物体迅速冲到某个位置(捕捉位置),捕捉到位置之后会带有一定的震动
    176  
    177  2.UISnapBehavior的初始化
    178  - (instancetype)initWithItem:(id <UIDynamicItem>)item snapToPoint:(CGPoint)point;
    179  
    180  3.UISnapBehavior常见属性
    181  @property (nonatomic, assign) CGFloat damping;
    182  用于减幅、减震(取值范围是0.0 ~ 1.0,值越大,震动幅度越小)
    183  
    184  UISnapBehavior使用注意
    185  如果要进行连续的捕捉行为,需要先把前面的捕捉行为从物理仿真器中移除
    186 
    187  */
    188 
    189 
    190 - (UIDynamicAnimator *)dynamic
    191 {
    192     if (!_dynamic) {
    193         _dynamic = [[UIDynamicAnimator alloc] initWithReferenceView:self.view];
    194     }
    195     return _dynamic;
    196 }
    197 
    198 - (void)viewDidLoad {
    199     [super viewDidLoad];
    200 }
    201 
    202 - (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event
    203 {
    204 //    [self createGravity];
    205 //    [self createCollision];
    206     [self createSnap:touches];
    207     
    208     
    209 }
    210 
    211 ///演示捕捉行为
    212 - (void)createSnap:(NSSet<UITouch *> *)touches
    213 {
    214     //获取当前触摸的手指
    215     UITouch *touch = [touches anyObject];
    216     //取出手指的位置
    217     CGPoint point = [touch locationInView:touch.view];
    218 
    219     // 1.创建物理仿真器
    220     
    221     // 2.创建物理仿真行为
    222     UISnapBehavior *snapB = [[UISnapBehavior alloc] initWithItem:self.redView snapToPoint:point];
    223     
    224     // 3.设置捕捉行为的减震
    225     snapB.damping = arc4random_uniform(5) / 10 + 0.3;
    226     
    227     //注意:吸附行为默认只吸附一次,如果多次吸附必须从仿真器中移除再重复添加
    228     [self.dynamic removeAllBehaviors];
    229     
    230     // 3.将物理仿真行为添加到物理仿真器中
    231     [self.dynamic addBehavior:snapB];
    232 
    233 }
    234 
    235 ///演示碰撞行为
    236 - (void)createCollision
    237 {
    238     // 1.创建物理仿真器
    239     
    240     // 2.创建物理仿真行为
    241     UIGravityBehavior *gravityB = [[UIGravityBehavior alloc] initWithItems:@[self.redView]];
    242     UICollisionBehavior *collisionB = [[UICollisionBehavior alloc] initWithItems:@[self.redView]];
    243     
    244     //设置碰撞边界
    245 //    collisionB.translatesReferenceBoundsIntoBoundary = YES;
    246     //添加直线边界
    247 //    [collisionB addBoundaryWithIdentifier:@"line" fromPoint:CGPointMake(0, 200) toPoint:CGPointMake(320, 420)];
    248     //添加图像边界
    249     UIBezierPath *path = [UIBezierPath bezierPathWithOvalInRect:self.view.frame];
    250     
    251     
    252     [collisionB addBoundaryWithIdentifier:@"bezier" forPath:path];
    253     
    254     
    255     // 3.将物理仿真行为添加到物理仿真器中
    256     [self.dynamic addBehavior:gravityB];
    257     [self.dynamic addBehavior:collisionB];
    258     
    259     // 此方法可以用于碰撞实际情况的跟踪
    260 //    collisionB.action = ^ {
    261 //        NSLog(@"%@", NSStringFromCGRect(self.redView.frame));
    262 //    };
    263 
    264 }
    265 
    266 ///演示重力行为
    267 - (void)createGravity
    268 {
    269     // 1.创建物理仿真器
    270     
    271     // 2.创建物理仿真行为
    272     UIGravityBehavior *gravityB = [[UIGravityBehavior alloc] initWithItems:@[self.redView]];
    273     
    274     //设置重力方向
    275     gravityB.gravityDirection = CGVectorMake(0, 1);
    276     //设置重力角度
    277     //gravityB.angle = M_PI_2;
    278     //设置加速度
    279     gravityB.magnitude = 50;
    280     
    281     // 3.将物理仿真行为添加到物理仿真器中
    282     [self.dynamic addBehavior:gravityB];
    283     
    284 }
    285 
    286 @end

    推动行为

      1 //
      2 //  PushView.m
      3 //  02.UIDynamic演练
      4 //
      5 //  Created by apple on 13-12-24.
      6 //  Copyright (c) 2013年 itcast. All rights reserved.
      7 //
      8 
      9 #import "PushView.h"
     10 
     11 @interface PushView()
     12 {
     13     UIPushBehavior  *_push;
     14     
     15     // 第一次按下的点
     16     CGPoint         _firstPoint;
     17     // 移动过程中的点
     18     CGPoint         _movePoint;
     19     
     20     UIImageView     *_imageView;
     21 }
     22 
     23 @end
     24 
     25 @implementation PushView
     26 /*
     27  皮筋效果,将方块弹射出去
     28  */
     29 - (id)initWithFrame:(CGRect)frame
     30 {
     31     self = [super initWithFrame:frame];
     32     
     33     if (self) {
     34         // 将方块下移
     35         self.box.center = CGPointMake(self.center.x, 200);
     36         // 旋转
     37         self.box.transform = CGAffineTransformMakeRotation(M_PI_4);
     38         
     39         UIView *blueView = [[UIView alloc] initWithFrame:CGRectMake(110, 300, 20, 20)];
     40         blueView.backgroundColor = [UIColor blueColor];
     41         [self addSubview:blueView];
     42         
     43         // 1. 定义手势
     44         UIPanGestureRecognizer *pan = [[UIPanGestureRecognizer alloc] initWithTarget:self action:@selector(pan:)];
     45         
     46         [self addGestureRecognizer:pan];
     47         
     48         // 2. 实例化推行为,单此推动
     49         _push = [[UIPushBehavior alloc] initWithItems:@[self.box] mode:UIPushBehaviorModeInstantaneous];
     50         
     51         [self.animator addBehavior:_push];
     52         
     53         // 3. 碰撞检测的行为
     54         UICollisionBehavior *collision = [[UICollisionBehavior alloc] initWithItems:@[self.box, blueView]];
     55         collision.translatesReferenceBoundsIntoBoundary = YES;
     56         
     57         [self.animator addBehavior:collision];
     58         
     59         // 4. 添加图像视图
     60         UIImage *image = [UIImage imageNamed:@"AttachmentPoint_Mask"];
     61         _imageView = [[UIImageView alloc] initWithImage:image];
     62         // 先隐藏
     63         _imageView.hidden = YES;
     64         [self addSubview:_imageView];
     65         
     66         // iOS7添加的对图像颜色处理的功能,过滤颜色的功能
     67         _imageView.tintColor = [UIColor blueColor];
     68         // 重新绘图
     69         _imageView.image = [_imageView.image imageWithRenderingMode:UIImageRenderingModeAlwaysTemplate];
     70     }
     71     
     72     return self;
     73 }
     74 
     75 #pragma mark - 拖动手势
     76 - (void)pan:(UIPanGestureRecognizer *)recognizer
     77 {
     78     // 取出手势所在的点
     79     CGPoint location = [recognizer locationInView:self];
     80     
     81     // 拖动手势是一个持续性手势,需要判断状态
     82     if (UIGestureRecognizerStateBegan == recognizer.state) {
     83         // 按下手指,皮筋起点在这里,需要记录住手指的位置
     84         _firstPoint = location;
     85         
     86         // 添加一个图像视图标记手指按下
     87         _imageView.hidden = NO;
     88         _imageView.center = location;
     89         
     90     } else if (UIGestureRecognizerStateChanged == recognizer.state) {
     91         // 根据手指改变,绘制皮筋
     92         // 移动的点也需要记录
     93         _movePoint = location;
     94         
     95         [self setNeedsDisplay];
     96         
     97     } else if (UIGestureRecognizerStateEnded == recognizer.state) {
     98         // 放开手指,反方向弹射方块,此时给方块一个推力
     99         /*
    100          angle          推的方向
    101          magnitude      力量
    102          active         单次推需要设置为YES,才能生效
    103          */
    104         CGPoint endPoint = location;
    105         CGPoint offset = CGPointMake(_firstPoint.x - endPoint.x, _firstPoint.y - endPoint.y);
    106         
    107         CGFloat distance = sqrtf(offset.x * offset.x + offset.y * offset.y);
    108         CGFloat angle = atan2f(offset.y, offset.x);
    109         
    110         // 推力的角度,方向
    111         _push.angle = angle;
    112         // 力量的大小
    113         _push.magnitude = distance / 10.0;
    114         
    115         // 对于单次推动,一定要设置成YES,才能够发力
    116         _push.active = YES;
    117         
    118         // 清理线,以及手指的图像视图
    119         _imageView.hidden = YES;
    120         _firstPoint = CGPointZero;
    121         _movePoint = CGPointZero;
    122         
    123         [self setNeedsDisplay];
    124     }
    125 }
    126 
    127 - (void)drawRect:(CGRect)rect
    128 {
    129     // 1. 上下文
    130     CGContextRef context = UIGraphicsGetCurrentContext();
    131     
    132     // 2. 设置路径
    133     CGContextMoveToPoint(context, _firstPoint.x, _firstPoint.y);
    134     CGContextAddLineToPoint(context, _movePoint.x, _movePoint.y);
    135     
    136     // 3. 设置绘制属性
    137     CGContextSetLineWidth(context, 5.0);
    138     // 颜色
    139     [[UIColor darkGrayColor] set];
    140     // 虚线
    141     CGFloat lengths[] = {20.0, 5.0};
    142     CGContextSetLineDash(context, 0.0, lengths, 2);
    143     
    144     // 4. 绘图
    145     CGContextDrawPath(context, kCGPathStroke);
    146 }
    147 
    148 @end

    附加行为

      1 //
      2 //  AttachmentView.m
      3 //  02.UIDynamic演练
      4 //
      5 //  Created by apple on 13-12-24.
      6 //  Copyright (c) 2013年 itcast. All rights reserved.
      7 //
      8 
      9 #import "AttachmentView.h"
     10 
     11 @interface AttachmentView()
     12 {
     13     
     14     UIImageView             *_anchorImage;
     15     UIImageView             *_offsetImage;
     16 }
     17 
     18 @end
     19 
     20 @implementation AttachmentView
     21 
     22 - (id)initWithFrame:(CGRect)frame
     23 {
     24     self = [super initWithFrame:frame];
     25     
     26     if (self) {
     27         // 下方块下移
     28         self.box.center = CGPointMake(self.center.x, 200);
     29         
     30         // 手势
     31         UIPanGestureRecognizer *pan = [[UIPanGestureRecognizer alloc] initWithTarget:self action:@selector(pan:)];
     32         
     33         [self addGestureRecognizer:pan];
     34         
     35         // 附加行为
     36         CGPoint anchor = CGPointMake(self.box.center.x, self.box.center.y - 100);
     37         
     38         UIOffset offset = UIOffsetMake(0, 0);
     39         
     40         UIAttachmentBehavior *attachment = [[UIAttachmentBehavior alloc] initWithItem:self.box offsetFromCenter:offset attachedToAnchor:anchor];
     41         
     42         [self.animator addBehavior:attachment];
     43         
     44         _attachment = attachment;
     45         
     46         // 定位点,使用一个图像视图
     47         UIImage *image = [UIImage imageNamed:@"AttachmentPoint_Mask"];
     48         
     49         UIImageView *anchorImage = [[UIImageView alloc] initWithImage:image];
     50         anchorImage.center = anchor;
     51         
     52         [self addSubview:anchorImage];
     53         
     54         _anchorImage = anchorImage;
     55         
     56         // 偏移点,轴,也是用一个图像视图
     57         UIImageView *offsetImage = [[UIImageView alloc] initWithImage:image];
     58         
     59         CGFloat x = self.box.bounds.size.width / 2 + offset.horizontal;
     60         CGFloat y = self.box.bounds.size.height / 2 + offset.vertical;
     61         
     62         offsetImage.center = CGPointMake(x, y);
     63         
     64         [self.box addSubview:offsetImage];
     65         
     66         _offsetImage = offsetImage;
     67         
     68         // 在两点之间画一条实线
     69     }
     70     
     71     return self;
     72 }
     73 
     74 #pragma mark - 拖动手势
     75 - (void)pan:(UIPanGestureRecognizer *)recognizer
     76 {
     77     if (UIGestureRecognizerStateChanged == recognizer.state) {
     78         CGPoint location = [recognizer locationInView:self];
     79         
     80         _attachment.anchorPoint = location;
     81         _anchorImage.center = location;
     82         
     83         [self setNeedsDisplay];
     84     }
     85 }
     86 
     87 - (void)drawRect:(CGRect)rect
     88 {
     89     CGContextRef context = UIGraphicsGetCurrentContext();
     90     
     91     // moveto
     92     CGContextMoveToPoint(context, _anchorImage.center.x, _anchorImage.center.y);
     93     
     94     // addline
     95     // 去偏移点相对于父视图的坐标
     96     CGPoint p = [self convertPoint:_offsetImage.center fromView:self.box];
     97     CGContextAddLineToPoint(context, p.x, p.y);
     98     
     99     CGFloat lengths[] = {10.0f, 8.0f};
    100     CGContextSetLineDash(context, 0.0, lengths, 2);
    101     
    102     CGContextSetLineWidth(context, 5.0f);
    103     
    104     CGContextDrawPath(context, kCGPathStroke);
    105 }
    106 
    107 
    108 @end
  • 相关阅读:
    【FIRST USE】第一次用git把代码上传到github
    [多线程学习笔记] 一个线程安全的队列
    C中宏展开问题
    C语言中的命名空间
    c语言中赋值语句的结果
    Python一些难以察觉的错误
    C语言中的内存压缩技术
    简述数据结构:二叉查找树
    指针与指针的引用、指针的指针
    C++ 中的virtual关键词
  • 原文地址:https://www.cnblogs.com/oc-bowen/p/5248013.html
Copyright © 2011-2022 走看看