美文网首页iOS
iOS UIDynamic物理效果

iOS UIDynamic物理效果

作者: 草原烈鹰 | 来源:发表于2017-01-13 15:18 被阅读96次
    各种碰撞、吸附、点击展开等物理视觉效果大都是通过UIDynamic来实现的

    直接上代码看各种效果:

    
    #import "ViewController.h"
    
    @interface ViewController ()<UICollisionBehaviorDelegate,UIGestureRecognizerDelegate>
    @property (strong, nonatomic) UIView *squareView;
    @property (strong, nonatomic) UIDynamicAnimator *animator;
    
    @property (nonatomic, strong) UIAttachmentBehavior *attachmentB;//附着行为
    @property (nonatomic, strong) NSMutableArray *itemsA;
    @property (nonatomic, strong) UIGravityBehavior *gravityB;//重力行为
    
    @property (assign, nonatomic) CGPoint curTickleStart;
    @property (nonatomic, assign) CGPoint oldCenter;
    @end
    
    @implementation ViewController
    
    - (void)viewDidLoad {
        [super viewDidLoad];
        
        
        self.squareView = [[UIView alloc] initWithFrame:CGRectMake(100, 100, 200, 200)];
        _squareView.backgroundColor = [UIColor orangeColor];
        [self.view addSubview:self.squareView];
        self.oldCenter = _squareView.center;
        
        self.itemsA = [NSMutableArray arrayWithCapacity:0];
        for (int i = 0; i<5; i++) {
            UIView *view1 = [[UIView alloc] initWithFrame:CGRectMake(10 + i * 30, 100, 20, 20)];
            view1.backgroundColor = [UIColor colorWithRed:arc4random()% 255 / 255.0 green:arc4random()% 255 / 255.0 blue:arc4random()% 255 / 255.0 alpha:1.0];
            [self.view addSubview:view1];
            [_itemsA addObject:view1];
        }
        
    
        
        self.animator = [[UIDynamicAnimator alloc] initWithReferenceView:self.view];
    //   NSArray *itemsArr = [self.animator itemsInRect:CGRectMake(0, 100, self.view.bounds.size.width, 50)];
    //    - (NSArray*)itemsInRect:(CGRect)rect; //只有在添加行为后,才有值
        //- (void)removeBehavior:(UIDynamicBehavior *)behavior;
        //- (void)removeAllBehaviors;
        //- (void)addBehavior:(UIDynamicBehavior *)behavior;
        
        
        
        
        self.gravityB = [[UIGravityBehavior alloc] initWithItems:_itemsA]; // 创建一个重力行为
        // 在进行动画时的 block 回调 @property(nonatomic, copy) void (^action)(void)
    //    _gravityB.action = ^{
    //        NSLog(@"ing animation");
    //    };
        _gravityB.gravityDirection = CGVectorMake(0.5, 0.8); // 在垂直向下方向 1000 点/平方秒 的速度 , 第一个参数是方向,第二个是速度
        [self.animator addBehavior:_gravityB];
        // 添加到该动态行为中的子动态行为 @property(nonatomic, readonly, copy) NSArray *childBehaviors
        //    gravity.childBehaviors;
        
        //  该动态行为相关联的dynamicAnimator
        //    @property(nonatomic, readonly) UIDynamicAnimator *dynamicAnimator
        
        //添加一个子动态行为
        //    - (void)addChildBehavior:(UIDynamicBehavior *)behavior
        
        // 移除一个子动态行为
        //    - (void)removeChildBehavior:(UIDynamicBehavior *)behavior
        
        // 当该动态行为将要被添加到一个UIDynamicAnimator中时,这个方法会被调用。
        //    - (void)willMoveToAnimator:(UIDynamicAnimator *)dynamicAnimator
        
        
        
        
        // 创建碰撞行为
        UICollisionBehavior *collision = [[UICollisionBehavior alloc] initWithItems:_itemsA];
        
        // 指定 Reference view 的边界为可碰撞边界
        collision.translatesReferenceBoundsIntoBoundary = YES;
        collision.collisionDelegate = self;
        // UICollisionBehaviorModeItems:item 只会和别的 item 发生碰撞;UICollisionBehaviorModeBoundaries:item 只和碰撞边界进行碰撞;UICollisionBehaviorModeEverything:item 和 item 之间会发生碰撞,也会和指定的边界发生碰撞。
        collision.collisionMode = UICollisionBehaviorModeEverything;
        
        [self.animator addBehavior:collision];
        
        
        //UICollisionBehavior通过下面两个方法来添加碰撞边界,可以根据贝塞尔曲线或者一条直线生成碰撞边界。
        //    - (void)addBoundaryWithIdentifier:(id <NSCopying>)identifier forPath:(UIBezierPath*)bezierPath;
        //    - (void)addBoundaryWithIdentifier:(id <NSCopying>)identifier fromPoint:(CGPoint)p1 toPoint:(CGPoint)p2;
        
        //UICollisionBehavior 里的 item 每次发生碰撞都可以通过 delegate 来监听事件。<UICollisionBehaviorDelegate>
        // item 与 item 之间开始碰撞。
        //    - (void)collisionBehavior:(UICollisionBehavior*)behavior beganContactForItem:(id <UIDynamicItem>)item1 withItem:(id <UIDynamicItem>)item2 atPoint:(CGPoint)p;
        //
        //    // item 与 item 之间结束碰撞。
        //    - (void)collisionBehavior:(UICollisionBehavior*)behavior endedContactForItem:(id <UIDynamicItem>)item1 withItem:(id <UIDynamicItem>)item2;
        //
        //
        //    // item 和边界开始碰撞
        //    - (void)collisionBehavior:(UICollisionBehavior*)behavior beganContactForItem:(id <UIDynamicItem>)item withBoundaryIdentifier:(id <NSCopying>)identifier atPoint:(CGPoint)p;
        //
        //    // item 和边界结束碰撞
        //    - (void)collisionBehavior:(UICollisionBehavior*)behavior endedContactForItem:(id <UIDynamicItem>)item withBoundaryIdentifier:(id <NSCopying>)identifier;
        
        
        
        
        
        
        //UIAttachmentBehavior 附着行为,让物体附着在某个点或另外一个物体上。可以设置附着点的到物体的距离,阻尼系数和振动频率等。
        /**
         / UIAttachmentBehaviorTypeAnchor类型的依赖行为的锚点,锚点与行为相关的动力动画的坐标系统有关。
         @property(readwrite, nonatomic) CGPoint anchorPoint
         
         // 吸附行为的类型
         @property(readonly, nonatomic) UIAttachmentBehaviorType attachedBehaviorType
         
         // 描述吸附行为减弱的阻力大小
         @property(readwrite, nonatomic) CGFloat damping
         
         // 吸附行为震荡的频率
         @property(readwrite, nonatomic) CGFloat frequency
         
         // 与吸附行为相连的动态项目,当吸附行为类型是UIAttachmentBehaviorTypeItems时有2个元素,当吸附行为类型是UIAttachmentBehaviorTypeAnchor时只有一个元素。
         @property(nonatomic, readonly, copy) NSArray *items
         
         // 吸附行为中的两个吸附点之间的距离,通常用这个属性来调整吸附的长度,可以创建吸附行为之后调用。系统基于你创建吸附行为的方法来自动初始化这个长度
         @property(readwrite, nonatomic) CGFloat length
         */
    //    UIAttachmentBehavior *attachment = [[UIAttachmentBehavior alloc] initWithItem:self.squareView attachedToAnchor:self.squareView.center];
    //    attachment.length = 200;
    //    attachment.damping = 0.5;
    //    attachment.frequency = 1;
    //    [self.animator addBehavior:attachment];
        
        
        
        
        
        
        //UIDynamicItemBehavior  物体属性,如密度、弹性系数、摩擦系数、阻力、转动阻力等。 接下来我们修改物体的物理属性,为了能看到这个效果,我们先删除 UIAttachmentBehavior 相关的代码,并在 - (void)viewDidAppear:(BOOL)animated 末尾添加如下代码:
        /**
         // 弹力,通常设置 0~1 之间
         @property (readwrite, nonatomic) CGFloat elasticity;
         
         // 摩擦力,0表示完全光滑无摩擦
         @property (readwrite, nonatomic) CGFloat friction;
         
         // 密度,一个 100x100 points(1 point 在 retina 屏幕上等于2像素,在普通屏幕上为1像素。)大小的物体,密度1.0,在上面施加 1.0 的力,会产生 100 point/平方秒 的加速度。
         @property (readwrite, nonatomic) CGFloat density;
         
         // 线性阻力,物体在移动过程中受到的阻力大小
         @property (readwrite, nonatomic) CGFloat resistance;
         
         // 旋转阻力,物体旋转过程中的阻力大小
         @property (readwrite, nonatomic) CGFloat angularResistance;
         
         // 是否允许旋转
         @property (readwrite, nonatomic) BOOL allowsRotation;
         */
        
        UIDynamicItemBehavior *itemBehavior = [[UIDynamicItemBehavior alloc] initWithItems:_itemsA];
        itemBehavior.elasticity = 1; // 改变弹性
        itemBehavior.allowsRotation = YES; // 允许旋转
        [itemBehavior addAngularVelocity:1 forItem:self.squareView]; // 让物体旋转
        
        [self.animator addBehavior:itemBehavior];
        
        
        
        
        
        
        //UIPushBehavior 对物体施加力,可以是持续性的力也可以是一次性的力。用一个向量(CGVector)来表示力的方向和大小。
        //这次我们通过手势来动态的为物体添加推力,首先注释重力行为的相关代码,然后在 - (void)viewDidAppear:(BOOL)animated 末尾添加如下代码
        /**
         // 推力模式,UIPushBehaviorModeContinuous:持续型。UIPushBehaviorModeInstantaneous:一次性推力。
         @property (nonatomic, readonly) UIPushBehaviorMode mode;
         
         // 推力是否被激活,在激活状态下,物体才会受到推力效果
         @property(nonatomic, readwrite) BOOL active
         
         // 推力的大小和方向
         @property (readwrite, nonatomic) CGVector pushDirection;
         */
        
    //    UITapGestureRecognizer *viewTapGesture = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(tapViewHandler:)];
    //    [self.view addGestureRecognizer:viewTapGesture];
        
        
        
        
        
        
        //UISnapBehavior 将一个物体钉在某一点。它只有一个初始化方法和一个属性。
        // 根据 item 和 point 来确定一个 item 要被定到哪个点上。
    //    - (instancetype)initWithItem:(id <UIDynamicItem>)item snapToPoint:(CGPoint)point;
    //    
    //    // 减震系数,范围在0.0~1.0
    //    @property (nonatomic, assign) CGFloat damping;
        
        
        
      //添加拖拽手势
            
            UIPanGestureRecognizer *panGes = [[UIPanGestureRecognizer alloc] initWithTarget:self action:@selector(handlePan:)];
            panGes.delegate = self;
            [self.squareView addGestureRecognizer:panGes];
       
        
    
    
    }
    
    - (void)tapViewHandler:(UITapGestureRecognizer *)gestureRecognizer
    {
        UIPushBehavior *push = [[UIPushBehavior alloc] initWithItems:@[self.squareView] mode:UIPushBehaviorModeInstantaneous];
        CGPoint location = [gestureRecognizer locationInView:self.view];
        CGPoint itemCenter = self.squareView.center;
        push.pushDirection = CGVectorMake((location.x - itemCenter.x) / 100, (location.y - itemCenter.y) / 100);
        [self.animator addBehavior:push];
    }
    
    //拖拽手势
    - (void) handlePan:(UIPanGestureRecognizer*) recognizer
    {
        
    
            CGPoint translation = [recognizer translationInView:self.view];
            NSLog(@"wgj:%lf,%lf",translation.x,translation.y);
            NSLog(@"wgj001:%lf,%lf",recognizer.view.center.x,recognizer.view.center.y);
            recognizer.view.center = CGPointMake(recognizer.view.center.x + translation.x,
                                                 recognizer.view.center.y + translation.y);
            [recognizer setTranslation:CGPointZero inView:self.view];//防止移动量累计增加
            
            CGPoint location = recognizer.view.center;
            CGFloat itemW = recognizer.view.bounds.size.width;
            CGFloat itemH = recognizer.view.bounds.size.height;
            CGFloat viewW = self.view.bounds.size.width;
            CGFloat viewH = self.view.bounds.size.height;
            
            if (recognizer.view.center.x < itemW * 0.5) {
                recognizer.view.center = CGPointMake(itemW * 0.5, location.y);
            }
            if (recognizer.view.center.y < itemH * 0.5) {
                recognizer.view.center = CGPointMake(location.x, itemH * 0.5);
            }
            if (recognizer.view.center.x > viewW - itemW * 0.5) {
                recognizer.view.center = CGPointMake(viewW - itemW * 0.5, location.y);
            }
            if (recognizer.view.center.y > viewH - itemH * 0.5) {
                recognizer.view.center = CGPointMake(location.x, viewH - itemH * 0.5);
            }
            
    
        
        if (recognizer.state == UIGestureRecognizerStateBegan) {
            
            [self.animator removeBehavior:self.attachmentB];
            //        [self.animator removeAllBehaviors];
            
        }
        
        
        if (recognizer.state == UIGestureRecognizerStateEnded) {
            
            [self.animator addBehavior:self.attachmentB];//添加吸附行为
        }
        
        
        //让小物体改变角度
        _gravityB.angle = 3;
        
    //
    //    if (recognizer.state == UIGestureRecognizerStateEnded) {
    //        
    //        CGPoint velocity = [recognizer velocityInView:self.view];
    //        CGFloat magnitude = sqrtf((velocity.x * velocity.x) + (velocity.y * velocity.y));
    //        CGFloat slideMult = magnitude / 200;
    //        NSLog(@"magnitude: %f, slideMult: %f", magnitude, slideMult);
    //        
    //        float slideFactor = 0.1 * slideMult; // Increase for more of a slide
    //        CGPoint finalPoint = CGPointMake(recognizer.view.center.x + (velocity.x * slideFactor),
    //                                         recognizer.view.center.y + (velocity.y * slideFactor));
    //        finalPoint.x = MIN(MAX(finalPoint.x, 0), self.view.bounds.size.width);
    //        finalPoint.y = MIN(MAX(finalPoint.y, 0), self.view.bounds.size.height);
    //        
    //        [UIView animateWithDuration:slideFactor*2 delay:0 options:UIViewAnimationOptionCurveEaseOut animations:^{
    //            recognizer.view.center = finalPoint;
    //        } completion:nil];
    //    }
        
    }
    
    - (UIAttachmentBehavior *)attachmentB
    {
        if (_attachmentB == nil) {
            self.attachmentB = [[UIAttachmentBehavior alloc] initWithItem:self.squareView attachedToAnchor:CGPointMake(150, 200)];
            _attachmentB.length = 0;
            _attachmentB.damping = 0.6;//阻尼
            _attachmentB.frequency = 1.2; //震频
    
        }
        return _attachmentB;
    }
    
    
    
    - (void)didReceiveMemoryWarning {
        [super didReceiveMemoryWarning];
        // Dispose of any resources that can be recreated.
    }
    
    @end
    
    

    相关文章

      网友评论

        本文标题:iOS UIDynamic物理效果

        本文链接:https://www.haomeiwen.com/subject/ifjsbttx.html