503-UIDynamic
一、简介
1.使用步骤
1)创建一个物理仿真器
// animator - (UIDynamicAnimator *)animator { if (!_animator) { _animator = [[UIDynamicAnimator alloc] initWithReferenceView:self.view]; } return _animator; }
2)创建相应的物理仿真行为
// 重力行为 UIGravityBehavior *gravity = [[UIGravityBehavior alloc] init];
3)添加物理仿真元素
// 添加物理仿真元素 [gravity addItem:self.redView];
4)将物理仿真行为添加到物理仿真器中,执行仿真
// 执行仿真,让物理仿真元素执行仿真行为 [self.animator addBehavior:gravity];
2.概念性名词
1)物理仿真元素
注意:不是任何的对象都可以做物理仿真元素,不是任何对象都能进行物理仿真
物理仿真元素要素:任何遵守了UIDynamicItem协议的对象
UIView默认已经遵守了UIDynamicItem协议,因此任何UI控件都能做物理仿真
2)物理仿真行为
UIGravityBehavior:重力行为
UICollisionBehavior:碰撞行为
UISnapBehavior:捕捉行为
UIPushBehavior:推动行为
UIAttachmentBehavior:附着行为
UIDynamicItemBehavior:动力元素行为
3)物理仿真器
它可以让物理仿真元素执行物理仿真行为,属于UIDynamicAnimator类型的对象
常见方法和属性
// 1.方法 - (void)addBehavior:(UIDynamicBehavior *)behavior; // 添加1个物理仿真行为 - (void)removeBehavior:(UIDynamicBehavior *)behavior; // 移除1个物理仿真行为 - (void)removeAllBehaviors; // 移除之前添加过的所有物理仿真行为 // 2.属性 @property (nonatomic, readonly) UIView* referenceView; // 参照视图 @property (nonatomic, readonly, copy) NSArray* behaviors; // 添加到物理仿真器中的所有物理仿真行为 @property (nonatomic, readonly, getter = isRunning) BOOL running; // 是否正在进行物理仿真 @property (nonatomic, assign) id <UIDynamicAnimatorDelegate> delegate; // 代理对象(能监听物理仿真器的仿真过程,比如开始和结束)
二、重力行为
1.说明
给定重力方向、加速度,让物体朝着重力方向掉落
2.方法
// 1.UIGravityBehavior的初始化 // items:存放着物理仿真元素的数组 - (instancetype)initWithItems:(NSArray *)items; // 2.添加1个物理仿真元素 - (void)addItem:(id <UIDynamicItem>)item; // 3.移除1个物理仿真元素 - (void)removeItem:(id <UIDynamicItem>)item;
3.属性
// 添加到重力行为中的所有物理仿真元素 @property (nonatomic, readonly, copy) NSArray* items; // 重力方向(是一个二维向量) @property (readwrite, nonatomic) CGVector gravityDirection; // 重力方向(是一个角度,以x轴正方向为0°,顺时针正数,逆时针负数) @property (readwrite, nonatomic) CGFloat angle; // 量级(用来控制加速度,1.0代表加速度是1000 points /second²) @property (readwrite, nonatomic) CGFloat magnitude;
4.代码实例
#import "GravityController.h" @interface GravityController () @property (nonatomic, strong) UIDynamicAnimator *animator; // 物理仿真器 @property (nonatomic, strong) UIView *redView; @end @implementation GravityController #pragma mark - 懒加载 // animator - (UIDynamicAnimator *)animator { if (!_animator) { _animator = [[UIDynamicAnimator alloc] initWithReferenceView:self.view]; } return _animator; } - (void)viewDidLoad { [super viewDidLoad]; [self initUI]; // 界面 } #pragma mark - 界面 - (void)initUI { self.view.backgroundColor = [UIColor whiteColor]; // redView _redView = [[UIView alloc] initWithFrame:CGRectMake(40, 70, 100, 100)]; _redView.backgroundColor = [UIColor redColor]; [self.view addSubview:_redView]; // btn UIButton *btn = [UIButton buttonWithType:UIButtonTypeSystem]; btn.frame = CGRectMake(20, 20, 100, 35); btn.tintColor = [UIColor whiteColor]; btn.backgroundColor = [UIColor orangeColor]; [btn setTitle:@"重力测试" forState:UIControlStateNormal]; btn.titleLabel.font = [UIFont systemFontOfSize:15]; [btn addTarget:self action:@selector(btnClick:) forControlEvents:UIControlEventTouchUpInside]; [self.view addSubview:btn]; } #pragma mark - 点击事件 - (void)btnClick:(UIButton *)sender { // 1.创建仿真行为 // 重力行为 UIGravityBehavior *gravity = [[UIGravityBehavior alloc] init]; // 1)设置重力的方向(角度和二维向量二选一) // a.角度设置(angle) // 角度坐标:水平向右是0°,垂直向下是90°,水平向左是180°,垂直向上是-90° gravity.angle = M_PI_2 - M_PI_4; // b.二维向量设置(gravityDirection) // 给定坐标平面内的一个点,然后用原点(0, 0)来连接它,就构成了一个向量 // gravity.gravityDirection = CGVectorMake(1, 0); // 2)设置重力的加速度 // 重力的加速度越大,碰撞就越厉害 // 速度:point/s // 加速度:point/s² gravity.magnitude = 10; [gravity addItem:self.redView]; // 2.添加物理仿真元素 [gravity addItem:self.redView]; // 3.将物理仿真行为添加到物理仿真器中,执行仿真 [self.animator addBehavior:gravity]; } @end
三、碰撞行为
1.简介
可以让物体之间实现碰撞效果,可以通过添加边界(boundary),让物理碰撞局限在某个空间中
2.UICollisionBehavior边界相关的方法
// 1.添加边界路径 - (void)addBoundaryWithIdentifier:(id <NSCopying>)identifier forPath:(UIBezierPath*)bezierPath; // 2.添加直线边界 - (void)addBoundaryWithIdentifier:(id <NSCopying>)identifier fromPoint:(CGPoint)p1 toPoint:(CGPoint)p2; // 3.返回指定标示符的边界路径 - (UIBezierPath*)boundaryWithIdentifier:(id <NSCopying>)identifier; // 4.移除指定标示符的边界 - (void)removeBoundaryWithIdentifier:(id <NSCopying>)identifier; // 5.移除所有边界 - (void)removeAllBoundaries; // 6.存放边界标示符的数组 @property (nonatomic, readonly, copy) NSArray* boundaryIdentifiers;
3.UICollisionBehavior常见属性和方法
// 1.是否以参照视图的bounds为边界 @property (nonatomic, readwrite) BOOL translatesReferenceBoundsIntoBoundary; // 2.碰撞模式(分为3种:元素碰撞、边界碰撞、全体碰撞) @property (nonatomic, readwrite) UICollisionBehaviorMode collisionMode; // 3.代理对象(可以监听元素的碰撞过程) @property (nonatomic, assign, readwrite) id <UICollisionBehaviorDelegate> collisionDelegate; // 4.设置参照视图的bounds为边界,并且设置内边距 - (void)setTranslatesReferenceBoundsIntoBoundaryWithInsets:(UIEdgeInsets)insets;
4.代码
#import "GravityCollisionController.h" @interface GravityCollisionController () @property (nonatomic, strong) UIDynamicAnimator *animator; // 物理仿真器 @property (nonatomic, strong) UIView *redView; @property (nonatomic, strong) UIProgressView *progressView; @property (nonatomic, strong) UISegmentedControl *segmentedControl; @end @implementation GravityCollisionController #pragma mark - 懒加载 // animator - (UIDynamicAnimator *)animator { if (!_animator) { _animator = [[UIDynamicAnimator alloc] initWithReferenceView:self.view]; } return _animator; } - (void)viewDidLoad { [super viewDidLoad]; [self initUI]; // 界面 } #pragma mark - 界面 - (void)initUI { self.view.backgroundColor = [UIColor whiteColor]; // redView _redView = [[UIView alloc] initWithFrame:CGRectMake(40, 70, 100, 100)]; _redView.backgroundColor = [UIColor redColor]; [self.view addSubview:_redView]; // progressView _progressView = [[UIProgressView alloc] initWithFrame:CGRectMake(10, 200, 200, 10)]; [self.view addSubview:_progressView]; // segmentedControl _segmentedControl = [[UISegmentedControl alloc] initWithItems:@[@"杨洋", @"任嘉伦", @"鹿晗"]]; _segmentedControl.frame = CGRectMake(30, 240, 150, 40); [self.view addSubview:_segmentedControl]; // btn UIButton *btn = [UIButton buttonWithType:UIButtonTypeSystem]; btn.frame = CGRectMake(20, 20, 120, 35); btn.tintColor = [UIColor whiteColor]; btn.backgroundColor = [UIColor orangeColor]; [btn setTitle:@"重力&碰撞测试" forState:UIControlStateNormal]; btn.titleLabel.font = [UIFont systemFontOfSize:15]; [btn addTarget:self action:@selector(btnClick:) forControlEvents:UIControlEventTouchUpInside]; [self.view addSubview:btn]; } #pragma mark - 点击事件 - (void)btnClick:(UIButton *)sender { [self testGravityAndCollsion1]; // 1.以参照视图的边框成为碰撞检测的边界 // [self testGravityAndCollision2]; // 2.以2根线段作为边界 // [self testGravityAndCollision3]; // 3.以圆作为边界 } #pragma mark - 重力行为+碰撞检测 // 1.以参照视图的边框成为碰撞检测的边界 - (void)testGravityAndCollsion1 { // 1.重力行为 UIGravityBehavior *gravity = [[UIGravityBehavior alloc] init]; [gravity addItem:self.redView]; // 2.碰撞行为 UICollisionBehavior *collision = [[UICollisionBehavior alloc] init]; [collision addItem:self.redView]; [collision addItem:self.progressView]; [collision addItem:self.segmentedControl]; // 让参照视图的边框成为碰撞检测的边界 collision.translatesReferenceBoundsIntoBoundary = YES; // 3.执行仿真 [self.animator addBehavior:gravity]; [self.animator addBehavior:collision]; } // 2.以2根线段作为边界 - (void)testGravityAndCollision2 { // 1.重力行为 UIGravityBehavior *gravity = [[UIGravityBehavior alloc] init]; [gravity addItem:self.redView]; // 2.碰撞检测行为 UICollisionBehavior *collision = [[UICollisionBehavior alloc] init]; [collision addItem:self.redView]; CGPoint startP = CGPointMake(50, 160); CGPoint endP = CGPointMake(320, 400); // 注意:这个标示符不能为空,可以为字符串,因为需要遵守NSCopying协议 [collision addBoundaryWithIdentifier:@"line1" fromPoint:startP toPoint:endP]; CGPoint startP1 = CGPointMake(320, 0); [collision addBoundaryWithIdentifier:@"line2" fromPoint:startP1 toPoint:endP]; // 3.开始仿真 [self.animator addBehavior:gravity]; [self.animator addBehavior:collision]; } // 3.以圆作为边界 - (void)testGravityAndCollision3 { // 1.重力行为 UIGravityBehavior *gravity = [[UIGravityBehavior alloc] init]; [gravity addItem:self.redView]; // 2.碰撞检测行为 UICollisionBehavior *collision = [[UICollisionBehavior alloc] init]; [collision addItem:self.redView]; // 添加一个椭圆为碰撞边界 UIBezierPath *path = [UIBezierPath bezierPathWithOvalInRect:CGRectMake(0, 0, 320, 200)]; [collision addBoundaryWithIdentifier:@"circle" forPath:path]; // 3.开始仿真 [self.animator addBehavior:gravity]; [self.animator addBehavior:collision]; }
四、捕捉行为
1.说明
可以让物体迅速冲到某个位置(捕捉位置),捕捉到位置之后会带有一定的震动
2.常见方法和属性
// 1.UISnapBehavior的初始化 - (instancetype)initWithItem:(id <UIDynamicItem>)item snapToPoint:(CGPoint)point; // 2.用于减幅、减震(取值范围是0.0 ~ 1.0,值越大,震动幅度越小) @property (nonatomic, assign) CGFloat damping;
3.UISnapBehavior使用注意
如果要进行连续的捕捉行为,需要先把前面的捕捉行为从物理仿真器中移除
4.代码实例
#import "SnapController.h" @interface SnapController () @property (nonatomic, strong) UIDynamicAnimator *animator; // 物理仿真器 @property (nonatomic, strong) UIView *redView; @end @implementation SnapController #pragma mark - 懒加载 // animator - (UIDynamicAnimator *)animator { if (!_animator) { _animator = [[UIDynamicAnimator alloc] initWithReferenceView:self.view]; } return _animator; } - (void)viewDidLoad { [super viewDidLoad]; [self initUI]; // 界面 } #pragma mark - 界面 - (void)initUI { self.view.backgroundColor = [UIColor whiteColor]; // redView _redView = [[UIView alloc] initWithFrame:CGRectMake(40, 70, 100, 100)]; _redView.backgroundColor = [UIColor redColor]; [self.view addSubview:_redView]; } #pragma mark - 触摸屏幕 - (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event { // 获取一个触摸点 UITouch *touch = [touches anyObject]; CGPoint point = [touch locationInView:touch.view]; // 1.创建捕捉行为 // 需要传入两个参数:一个是物理仿真元素,一个是捕捉点 UISnapBehavior *snap = [[UISnapBehavior alloc] initWithItem:self.redView snapToPoint:point]; // 设置防震系数(0-1,数值越大,震动的幅度越小) snap.damping = arc4random_uniform(10) / 10.0; // 2.执行捕捉行为 // 注意:这个控件只能用在一个仿真行为上,如果要拥有持续的仿真行为,那么需要把之前的所有仿真行为删除 // 删除之前的所有仿真行为 [self.animator removeAllBehaviors]; [self.animator addBehavior:snap]; } @end

浙公网安备 33010602011771号