1.什麼是UIDynamic
UIDynamic是從iOS 7開始引入的一種新技術,隸屬於UIKit框架能夠認爲是一種物理引擎,能模擬和仿真現實生活中的物理現象如:重力、彈性碰撞等現象app
2.物理引擎的價值
普遍用於遊戲開發,經典成功案例是「憤怒的小鳥」,讓開發人員能夠在遠離物理學公式的狀況下,實現炫酷的物理仿真效果提升了遊戲開發效率,產生更多優秀好玩的物理仿真遊戲框架
3.知名的2D物理引擎
Box2d
Chipmunk學習
要想使用UIDynamic來實現物理仿真效果,大體的步驟以下:動畫
1.建立一個物理仿真器(順便設置仿真範圍)
2.建立相應的物理仿真行爲(順便添加物理仿真元素)
3.將物理仿真行爲添加到物理仿真器中開始仿真atom
1.三個概念代理
2.物理仿真元素
注意:
不是任何對象都能作物理仿真元素
不是任何對象都能進行物理仿真code
物理仿真元素要素:
任何遵照了UIDynamicItem協議的對象
UIView默認已經遵照了UIDynamicItem協議,所以任何UI控件都能作物理仿真orm
UICollectionViewLayoutAttributes類默認也遵照UIDynamicItem協議對象
3.物理仿真行爲blog
(1)UIDynamic提供瞭如下幾種物理仿真行爲
UIGravityBehavior:重力行爲
UICollisionBehavior:碰撞行爲
UISnapBehavior:捕捉行爲
UIPushBehavior:推進行爲
UIAttachmentBehavior:附着行爲
UIDynamicItemBehavior:動力元素行爲
(2)物理仿真行爲須知
上述全部物理仿真行爲都繼承自UIDynamicBehavior,全部的UIDynamicBehavior均可以獨立進行組合使用多種行爲時,能夠實現一些比較複雜的效果
4.物理仿真器
(1)物理仿真器須知
它可讓物理仿真元素執行物理仿真行爲
它是UIDynamicAnimator類型的對象
(2)UIDynamicAnimator的初始化
- (instancetype)initWithReferenceView:(UIView *)view;
view參數:是一個參照視圖,表示物理仿真的範圍
5.物理仿真器的說明
(1)UIDynamicAnimator的常見方法
//移除以前添加過的全部物理仿真行爲 - (void)addBehavior:(UIDynamicBehavior *)behavior; //移除以前添加過的全部物理仿真行爲 - (void)removeBehavior:(UIDynamicBehavior *)behavior; //添加1個物理仿真行爲 - (void)removeAllBehaviors;
(2)UIDynamicAnimator的常見屬性
//參照視圖 @property (nonatomic, readonly) UIView* referenceView; //添加到物理仿真器中的全部物理仿真行爲 @property (nonatomic, readonly, copy) NSArray* behaviors; //是否正在進行物理仿真 @property (nonatomic, readonly, getter = isRunning) BOOL running; //代理對象(能監聽物理仿真器的仿真過程,好比開始和結束) @property (nonatomic, assign) id
先看效果吧
最後是代碼
#import <UIKit/UIKit.h> @interface SecondViewController : UIViewController @property (weak, nonatomic) IBOutlet UIView *blueView; @property (weak, nonatomic) IBOutlet UIView *orangeView; @property (weak, nonatomic) IBOutlet UISegmentedControl *segmented; @property (weak, nonatomic) IBOutlet UIView *redView; @property (nonatomic,strong) UIDynamicAnimator *animator; @end #import "SecondViewController.h" @interface SecondViewController () @property (nonatomic,strong)UISnapBehavior *snapBehavior; @property (nonatomic,strong)UIPushBehavior *pushBehavior; @property (nonatomic,strong)UIAttachmentBehavior *attachmentBehavior; @end @implementation SecondViewController - (void)viewDidLoad { [super viewDidLoad]; self.blueView.transform = CGAffineTransformMakeRotation(M_PI_4); self.segmented.transform = CGAffineTransformMakeRotation(-M_PI / 8); if (!_pushBehavior) { _pushBehavior = [[UIPushBehavior alloc]initWithItems:@[_blueView] mode:UIPushBehaviorModeContinuous]; } _pushBehavior.active = YES; _pushBehavior.pushDirection = CGVectorMake(10.0f, 10.0f); _pushBehavior.magnitude = 1.0f; [self.animator addBehavior:_pushBehavior]; } - (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent: (UIEvent *)event { _pushBehavior.active = NO; //建立重力行爲 UIGravityBehavior *gravityBehavior = [[UIGravityBehavior alloc]init]; [gravityBehavior addItem:self.blueView]; [gravityBehavior addItem:self.orangeView]; [gravityBehavior addItem:self.segmented]; gravityBehavior.gravityDirection = CGVectorMake(-0.3f, 1.0f); //加速度 gravityBehavior.magnitude = 3; //建立碰撞行爲 UICollisionBehavior *collisionBehavior = [[UICollisionBehavior alloc]init]; //碰撞類型爲元素和邊界 collisionBehavior.collisionMode = UICollisionBehaviorModeEverything; CGFloat Y = self.view.frame.size.height - CGRectGetHeight(self.redView.frame); CGFloat X = self.view.frame.size.width; CGFloat height = self.view.frame.size.height; //設置紅色的View爲底邊界,左邊框跟右邊框做爲邊界 [collisionBehavior addBoundaryWithIdentifier:@"collision1" fromPoint:CGPointMake(0,Y) toPoint:CGPointMake(X, Y)]; [collisionBehavior addBoundaryWithIdentifier:@"collision2" fromPoint:CGPointMake(0, 0) toPoint:CGPointMake(0, height)]; [collisionBehavior addBoundaryWithIdentifier:@"collision3" fromPoint:CGPointMake(X,0) toPoint:CGPointMake(X, height)]; [collisionBehavior addItem:self.blueView]; [collisionBehavior addItem:self.segmented]; [collisionBehavior addItem:self.orangeView]; [self.animator addBehavior:collisionBehavior]; [self.animator addBehavior:gravityBehavior]; UIDynamicItemBehavior *itemBehavior = [[UIDynamicItemBehavior alloc] initWithItems:@[self.blueView]]; [itemBehavior setElasticity:0.5]; [self.animator addBehavior:itemBehavior]; UITapGestureRecognizer *tap = [[UITapGestureRecognizer alloc]initWithTarget:self action:@selector(tapGesture:)]; [self.view addGestureRecognizer:tap]; } - (void)tapGesture:(UITapGestureRecognizer *)gesture { CGPoint tapPoint = [gesture locationInView:self.view]; if (_snapBehavior) { [self.animator removeBehavior:_snapBehavior]; _snapBehavior = nil; } _snapBehavior = [[UISnapBehavior alloc]initWithItem:self.blueView snapToPoint:tapPoint]; _snapBehavior.action = ^(){ NSLog(@"UISnapBehavior 在執行"); }; _snapBehavior.damping = 0.9; [self.animator addBehavior:_snapBehavior]; } - (UIDynamicAnimator *)animator{ if (_animator == nil) { _animator = [[UIDynamicAnimator alloc]init]; } return _animator; } - (void)panGestureRecognizer:(UIPanGestureRecognizer *)gesture { CGPoint location = [gesture locationInView:self.view]; CGPoint imageLocation = [gesture locationInView:self.orangeView]; switch (gesture.state) { case UIGestureRecognizerStateBegan: { NSLog(@"touch position %@",NSStringFromCGPoint(location)); NSLog(@"loction in image %@",NSStringFromCGPoint(imageLocation)); [self.animator removeAllBehaviors]; UIOffset centerOffset = UIOffsetMake(imageLocation.x - CGRectGetMidX(self.orangeView.bounds), imageLocation.y - CGRectGetMidY(self.orangeView.bounds)); _attachmentBehavior = [[UIAttachmentBehavior alloc]initWithItem:self.orangeView offsetFromCenter:centerOffset attachedToAnchor:location]; _attachmentBehavior.damping = 0.5; _attachmentBehavior.frequency = 0.8; [self.animator addBehavior:_attachmentBehavior]; } break; case UIGestureRecognizerStateEnded: { [self.animator removeBehavior:_attachmentBehavior]; } break; default: { [_attachmentBehavior setAnchorPoint:[gesture locationInView:self.view]]; } break; } } - (void)didReceiveMemoryWarning { [super didReceiveMemoryWarning]; // Dispose of any resources that can be recreated. } /* #pragma mark - Navigation // In a storyboard-based application, you will often want to do a little preparation before navigation - (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender { // Get the new view controller using [segue destinationViewController]. // Pass the selected object to the new view controller. } */ @end
UIKit動力學的部分介紹完了.
最開始項目中只是用到了重力跟碰撞行爲,參考學習了:UIDynamic 詳細用法 中的案例.而後本身又展開了解了下UIKit動力學的知識,把捕捉行爲,推進行爲加了進去,作個完善.整理了一下.就是這樣.