动力学,手把手的搞动画


两个类~直接跑跑看撒~得意


//

//  DLCardView.h
//  dielianw
//
//  Created by 刘威 on 16/8/10.
//  Copyright © 2016年 apple. All rights reserved.
//


#import <UIKit/UIKit.h>


@interface DLCardView : UIView


@end








//
//  DLCardView.m
//  dielianw
//
//  Created by 刘威 on 16/8/10.
//  Copyright © 2016年 apple. All rights reserved.
//


#import "DLCardView.h"
#import "DLCardFrameModel.h"


#define ATTACHMENTVIEWHEIGHT (SCREEN_WIDTH - 80)
#define SCREEN_WIDTH ([UIScreen mainScreen].bounds.size.width)
#define SCREEN_HEIGHT ([UIScreen mainScreen].bounds.size.height)


@interface DLCardView ()<UICollisionBehaviorDelegate>


@property (strong, nonatomic) UIDynamicAnimator *dynamicAnimator;
@property (strong, nonatomic) UIAttachmentBehavior *attachmentBehavior;
@property (strong, nonatomic) UISnapBehavior *snapBehavior;
@property (assign, nonatomic) CGPoint attachmentViewCenter;
@property (strong, nonatomic) UIView *attachmentView;


@property (strong, nonatomic) NSMutableArray *viewArray;
@property (strong, nonatomic) NSMutableArray *frameArray;


@property (strong, nonatomic) DLCardFrameModel *firstViewFrameModel;
@property (strong, nonatomic) DLCardFrameModel *lastViewFrameModel;




@end


@implementation DLCardView


- (instancetype)initWithFrame:(CGRect)frame {
    self = [super initWithFrame:frame];
    if (self) {
        _viewArray = [NSMutableArray array];
        _frameArray = [NSMutableArray array];
        
        _lastViewFrameModel = [[DLCardFrameModel alloc] initWithRotation:0
                                                                   scale:1
                                                                       x:SCREEN_WIDTH / 2
                                                                       y:SCREEN_HEIGHT - 80 - ATTACHMENTVIEWHEIGHT / 2
                                                                  hidden:NO];
        
        
        
        DLCardFrameModel *model1 = [[DLCardFrameModel alloc] initWithRotation:-M_PI_2 / 8
                                                                        scale:0.9
                                                                            x:_lastViewFrameModel.x + 23 * (SCREEN_WIDTH / 320)
                                                                            y:_lastViewFrameModel.y - 50 * (SCREEN_WIDTH / 320)
                                                                       hidden:NO];
        
        DLCardFrameModel *model2 = [[DLCardFrameModel alloc] initWithRotation:-M_PI_2 / 8 * 2
                                                                        scale:0.8
                                                                            x:model1.x + 15 * (SCREEN_WIDTH / 320)
                                                                            y:model1.y - 50 * (SCREEN_WIDTH / 320)
                                                                       hidden:NO];
        
        DLCardFrameModel *model3 = [[DLCardFrameModel alloc] initWithRotation:-M_PI_2 / 8 * 3
                                                                        scale:0.7
                                                                            x:model2.x
                                                                            y:model2.y - 50 * (SCREEN_WIDTH / 320)
                                                                       hidden:NO];
        
        DLCardFrameModel *model4 = [[DLCardFrameModel alloc] initWithRotation:-M_PI_2 / 8 * 4
                                                                        scale:0.6
                                                                            x:model3.x - 10 * (SCREEN_WIDTH / 320)
                                                                            y:model3.y - 45 * (SCREEN_WIDTH / 320)
                                                                       hidden:NO];
        
        DLCardFrameModel *model5 = [[DLCardFrameModel alloc] initWithRotation:-M_PI_2 / 8 * 5
                                                                        scale:0.5
                                                                            x:model4.x - 20 * (SCREEN_WIDTH / 320)
                                                                            y:model4.y - 35 * (SCREEN_WIDTH / 320)
                                                                       hidden:NO];
        
        DLCardFrameModel *model6 = [[DLCardFrameModel alloc] initWithRotation:-M_PI_2 / 8 * 6
                                                                        scale:0.4
                                                                            x:model5.x - 25 * (SCREEN_WIDTH / 320)
                                                                            y:model5.y - 25 * (SCREEN_WIDTH / 320)
                                                                       hidden:NO];
        
        _firstViewFrameModel = [[DLCardFrameModel alloc] initWithRotation:-M_PI_2 / 8 * 7
                                                                    scale:0.3
                                                                        x:model6.x - 25 * (SCREEN_WIDTH / 320)
                                                                        y:model6.y - 25 * (SCREEN_WIDTH / 320)
                                                                   hidden:YES];
        
        [_frameArray addObject:_firstViewFrameModel];
        [_frameArray addObject:model6];
        [_frameArray addObject:model5];
        [_frameArray addObject:model4];
        [_frameArray addObject:model3];
        [_frameArray addObject:model2];
        [_frameArray addObject:model1];
        [_frameArray addObject:_lastViewFrameModel];
        
        
        for (NSInteger i = 0; i < _frameArray.count; i++) {
            UIView *view = [[UIView alloc] initWithFrame:CGRectMake((SCREEN_WIDTH - ATTACHMENTVIEWHEIGHT) / 2, SCREEN_HEIGHT - 80 - ATTACHMENTVIEWHEIGHT, ATTACHMENTVIEWHEIGHT, ATTACHMENTVIEWHEIGHT)];
            DLCardFrameModel *model = _frameArray[i];
            view.center = model.point;
            view.layer.masksToBounds = YES;
            view.layer.cornerRadius = 20;
            view.backgroundColor = [UIColor randomColor];
            [self addSubview:view];


            NSTimeInterval time = 0.4 - 0.02 * i;
            [self setDynamicWithView:view model:model duration:time];
            view.hidden = model.hidden;
            if (i == _frameArray.count - 1) {
                _attachmentView = view;
                _attachmentView.userInteractionEnabled = YES;
            }
            
            [_viewArray addObject:view];
        }
        
        
        _attachmentViewCenter = _attachmentView.center;
        _dynamicAnimator = [[UIDynamicAnimator alloc] initWithReferenceView:self];
        
        UIPanGestureRecognizer *pan = [[UIPanGestureRecognizer alloc] initWithTarget:self action:@selector(panAction:)];
        [_attachmentView addGestureRecognizer:pan];
    }
    return self;
}




- (void)panAction:(UIPanGestureRecognizer *)panGesture {
    CGPoint location = [panGesture locationInView:self];
    CGPoint p = panGesture.view.center;
    if (panGesture.state == UIGestureRecognizerStateBegan) {
        [_dynamicAnimator removeAllBehaviors];
        [_dynamicAnimator removeBehavior:_snapBehavior];
        _snapBehavior = nil;


        _attachmentBehavior = [[UIAttachmentBehavior alloc]initWithItem:panGesture.view offsetFromCenter:UIOffsetMake(-(p.x - location.x), -(p.y - location.y)) attachedToAnchor:location];
        _attachmentBehavior.damping = 100;
        _attachmentBehavior.length = 0;
        [_dynamicAnimator addBehavior:_attachmentBehavior];
        
    } else if (panGesture.state == UIGestureRecognizerStateChanged) {
        
        _attachmentBehavior.anchorPoint = location;
        
        double distance = sqrt(pow(_attachmentViewCenter.x - location.x, 2) + pow(_attachmentViewCenter.y - location.y, 2));


        
    } else if (panGesture.state == UIGestureRecognizerStateEnded ||
               panGesture.state == UIGestureRecognizerStateCancelled) {
        [_dynamicAnimator removeBehavior:_attachmentBehavior];
        [_dynamicAnimator removeBehavior:_snapBehavior];
        [_dynamicAnimator removeAllBehaviors];
        
        if (p.x < 120) {


            CGVector directionVector = CGVectorMake((p.x - _attachmentViewCenter.x) * 0.8, p.y - _attachmentViewCenter.y);
            UIPushBehavior *pushBehavior = [self pushBehaviorToPushView:_attachmentView direction:directionVector];
            [_dynamicAnimator addBehavior:pushBehavior];
            
            NSInteger angle;
            if (location.y < p.y) {
                angle = -5;
            } else angle = 5;
            
            UIDynamicItemBehavior *itemBehavior = [[UIDynamicItemBehavior alloc] initWithItems:@[_attachmentView]];
            itemBehavior.friction = 0.2;
            itemBehavior.allowsRotation = YES;
            [itemBehavior addAngularVelocity:angle forItem:_attachmentView];
            [_dynamicAnimator addBehavior:itemBehavior];
            
            dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(0.5 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
                [self loadNextSubcardView:_attachmentView];
            });
        } else {
            [_dynamicAnimator removeBehavior:_attachmentBehavior];
            _attachmentBehavior = nil;
    
            _snapBehavior = [self snapBehaviorFromSnapView:_attachmentView toPoint:_attachmentViewCenter];
            [_dynamicAnimator addBehavior:_snapBehavior];
        }
    } else {
        [_dynamicAnimator removeBehavior:_attachmentBehavior];
        _attachmentBehavior = nil;
        
        _snapBehavior = [self snapBehaviorFromSnapView:_attachmentView toPoint:_attachmentViewCenter];
        [_dynamicAnimator addBehavior:_snapBehavior];
    }
}


- (void)loadNextSubcardView:(UIView *)view {
    [_viewArray removeObject:view];
    [view removeFromSuperview];
    view = nil;
    
    UIView *lastView = _viewArray[_viewArray.count - 1];
    _attachmentView = lastView;
    UIPanGestureRecognizer *pan = [[UIPanGestureRecognizer alloc] initWithTarget:self action:@selector(panAction:)];
    [_attachmentView addGestureRecognizer:pan];
    
    UIView *newView = [[UIView alloc] initWithFrame:CGRectMake((SCREEN_WIDTH - ATTACHMENTVIEWHEIGHT) / 2, SCREEN_HEIGHT - 80 - ATTACHMENTVIEWHEIGHT, ATTACHMENTVIEWHEIGHT, ATTACHMENTVIEWHEIGHT)];
    newView.layer.masksToBounds = YES;
    newView.layer.cornerRadius = 20;
    newView.backgroundColor = [UIColor randomColor];
    [self addSubview:newView];
    newView.userInteractionEnabled = NO;
    newView.hidden = YES;
    
    CGAffineTransform t = CGAffineTransformMakeRotation(_firstViewFrameModel.rotation);
    newView.transform = CGAffineTransformScale(t, _firstViewFrameModel.scale, _firstViewFrameModel.scale);


    
    [_viewArray insertObject:newView atIndex:0];
    [_viewArray enumerateObjectsUsingBlock:^(id  _Nonnull obj, NSUInteger idx, BOOL * _Nonnull stop) {
        UIView *view = _viewArray[idx];
        DLCardFrameModel *model = _frameArray[idx];
        NSTimeInterval time = 0.4 - 0.02 * idx;
        [self setDynamicWithView:view model:model duration:time];
    }];
    _attachmentView.userInteractionEnabled = YES;
}


- (UIPushBehavior *)pushBehaviorToPushView:(UIView *)view direction:(CGVector)direction {
    if (!view) {
        return nil;
    }
    UIPushBehavior *pushBehavior = [[UIPushBehavior alloc] initWithItems:@[view] mode:UIPushBehaviorModeInstantaneous];
    pushBehavior.pushDirection = direction;
    return pushBehavior;
}


- (UICollisionBehavior *)collisionBehaviorThatBoundsView:(UIView *)view inRect:(CGRect)rect {
    if (!view) {
        return nil;
    }
    UICollisionBehavior *collisionBehavior =
    [[UICollisionBehavior alloc] initWithItems:@[ view ]];
    UIBezierPath *collisionBound = [UIBezierPath bezierPathWithRect:rect];
    [collisionBehavior addBoundaryWithIdentifier:@"c" forPath:collisionBound];
    collisionBehavior.collisionMode = UICollisionBehaviorModeBoundaries;
    return collisionBehavior;
}




- (UISnapBehavior *)snapBehaviorFromSnapView:(UIView *)view toPoint:(CGPoint)point {
    if (!view) {
        return nil;
    }
    UISnapBehavior *snapBehavior = [[UISnapBehavior alloc] initWithItem:view snapToPoint:point];
    snapBehavior.damping = 0.75f;
    return snapBehavior;
}


#pragma mark - UICollisionBehaviorDelegate


- (void)collisionBehavior:(UICollisionBehavior *)behavior endedContactForItem:(id<UIDynamicItem>)item withBoundaryIdentifier:(id<NSCopying>)identifier {
    NSMutableSet *viewsToRemove = [[NSMutableSet alloc] init];
    
    for (id aBehavior in _dynamicAnimator.behaviors) {
        if ([aBehavior isKindOfClass:[UIAttachmentBehavior class]]) {
            NSArray *items = ((UIAttachmentBehavior *)aBehavior).items;
            if ([items containsObject:item]) {
                [_dynamicAnimator removeBehavior:aBehavior];
                [viewsToRemove addObjectsFromArray:items];
            }
        }
        if ([aBehavior isKindOfClass:[UIPushBehavior class]]) {
            NSArray *items = ((UIPushBehavior *)aBehavior).items;
            if ([((UIPushBehavior *)aBehavior).items containsObject:item]) {
                if ([items containsObject:item]) {
                    [_dynamicAnimator removeBehavior:aBehavior];
                    [viewsToRemove addObjectsFromArray:items];
                }
            }
        }
        if ([aBehavior isKindOfClass:[UICollisionBehavior class]]) {
            NSArray *items = ((UICollisionBehavior *)aBehavior).items;
            if ([((UICollisionBehavior *)aBehavior).items
                 containsObject:item]) {
                if ([items containsObject:item]) {
                    [_dynamicAnimator removeBehavior:aBehavior];
                    [viewsToRemove addObjectsFromArray:items];
                }
            }
        }
    }
}




#pragma mark - dynamic
- (void)setDynamicWithView:(UIView *)view model:(DLCardFrameModel *)model duration:(NSTimeInterval)duration{
    [UIView animateWithDuration:duration delay:0.0 options:UIViewAnimationOptionCurveEaseInOut
                     animations:^(void) {
                         
                         view.userInteractionEnabled = NO;
                         view.hidden = model.hidden;
                         
                         CGAffineTransform t = CGAffineTransformMakeRotation(model.rotation);
                         view.transform = CGAffineTransformScale(t, model.scale, model.scale);
                         view.center = CGPointMake(model.x, model.y);
                         if (_attachmentView) {
                             [self insertSubview:view belowSubview:_attachmentView];
                         }
                     }completion:nil];
}


- (void)movieViewWithDistance:(CGFloat)distance view:(UIView *)view{


    CABasicAnimation *postionAnimation = [CABasicAnimation animationWithKeyPath:@"position.y"];
    postionAnimation.duration = 5;
    postionAnimation.fromValue = @(view.center.y);
    postionAnimation.toValue = @(view.center.y - distance);
    postionAnimation.removedOnCompletion = NO;
    postionAnimation.delegate = self;
    postionAnimation.autoreverses = NO;
    postionAnimation.fillMode = kCAFillModeForwards;
    postionAnimation.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseOut];
    [view.layer addAnimation:postionAnimation forKey:@"posstionAnimation"];
}


@end




//
//  DLCardFrameModel.h
//  dielianw
//
//  Created by 刘威 on 16/8/10.
//  Copyright © 2016年 apple. All rights reserved.
//


#import <Foundation/Foundation.h>


@interface DLCardFrameModel : NSObject


@property (assign, nonatomic, readonly) CGFloat rotation;
@property (assign, nonatomic          ) CGFloat scale;
@property (assign, nonatomic, getter = getPoint) CGPoint point;
@property (assign, nonatomic, readonly) CGFloat x;
@property (assign, nonatomic          ) CGFloat y;
@property (assign, nonatomic, readonly) BOOL hidden;


- (instancetype)initWithRotation:(CGFloat)rotation  scale:(CGFloat)scale x:(CGFloat)x y:(CGFloat)y hidden:(BOOL)hidden;


@end


//
//  DLCardFrameModel.m
//  dielianw
//
//  Created by 刘威 on 16/8/10.
//  Copyright © 2016年 apple. All rights reserved.
//


#import "DLCardFrameModel.h"


@implementation DLCardFrameModel


- (instancetype)initWithRotation:(CGFloat)rotation  scale:(CGFloat)scale x:(CGFloat)x y:(CGFloat)y hidden:(BOOL)hidden{
    if (self = [super init]) {
        _rotation = rotation;
        _scale = scale;
        _x = x;
        _y = y;
        _hidden = hidden;
    }
    return self;
}


- (CGPoint)getPoint {
    _point = CGPointMake(_x, _y);
    return _point;
}


@end

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值