UIKIit動力學(二)

#import <UIKit/UIKit.h>

@interface ViewController : UIViewController

@end

#import "ViewController.h"
#import "DraggableView.h"
#import "TearOffBehavior.h"
#import "DefaultBehavior.h"

const CGFloat kShapeDimension = 60.0;
const NSUInteger kSliceCount = 6;

@interface ViewController ()
@property (nonatomic) UIDynamicAnimator *animator;
@property (nonatomic) DefaultBehavior *defaultBehavior;
@end

@implementation ViewController

- (void)viewDidLoad {
    [super viewDidLoad];
    self.animator = [[UIDynamicAnimator alloc] initWithReferenceView:self.view];
    
    CGRect frame = CGRectMake(0, 0,
                              kShapeDimension,
                              kShapeDimension);
    
    DraggableView *dragView = [[DraggableView alloc] initWithFrame:frame
                                                          animator:self.animator];
    
    dragView.center = CGPointMake(self.view.center.x / 4,
                                  self.view.center.y / 4);
    dragView.alpha = 0.5;
    [self.view addSubview:dragView];
    
    DefaultBehavior *defaultBehavior = [DefaultBehavior new];
    [self.animator addBehavior:defaultBehavior];
    self.defaultBehavior = defaultBehavior;
    
    TearOffBehavior *tearOffBehavior = [[TearOffBehavior alloc]
                                        initWithDraggableView:dragView
                                        anchor:dragView.center
                                        handler:^(DraggableView *tornView,
                                                  DraggableView *newPinView) {
                                            tornView.alpha = 1;
                                            [defaultBehavior addItem:tornView];//每一個視圖 默認添加碰撞和重力效果
                                            
                                            // Double-tap to trash    雙擊手勢讓視圖消失
                                            UITapGestureRecognizer *
                                            tap = [[UITapGestureRecognizer alloc]
                                                   initWithTarget:self
                                                   action:@selector(trash:)];
                                            tap.numberOfTapsRequired = 2;
                                            [tornView addGestureRecognizer:tap];
                                        }];
    
    [self.animator addBehavior:tearOffBehavior];
    
}

- (void)trash:(UIGestureRecognizer *)g {
    UIView *view = g.view;
#pragma mark BEGIN 爆炸效果
    // Calculate the new views.
    NSArray *subviews = [self sliceView:view
                               intoRows:kSliceCount
                                columns:kSliceCount];
    
    // Create a new animator
    UIDynamicAnimator *
    trashAnimator = [[UIDynamicAnimator alloc]
                     initWithReferenceView:self.view];
    
    // Create a new default behavior
    DefaultBehavior *defaultBehavior = [DefaultBehavior new];
    
    for (UIView *subview in subviews) {
        // Add the new "exploded" view to the hierarchy
        [self.view addSubview:subview];
        [defaultBehavior addItem:subview];
        
        // Create a push animation for each
        UIPushBehavior *
        push = [[UIPushBehavior alloc]
                initWithItems:@[subview]
                mode:UIPushBehaviorModeInstantaneous];
        [push setPushDirection:CGVectorMake((float)rand()/RAND_MAX - .5,
                                            (float)rand()/RAND_MAX - .5)];
        [trashAnimator addBehavior:push];
        
        // Fade out the pieces as they fly around.
        // At the end, remove them. Referencing trashAnimator here
        // also allows ARC to keep it around without an ivar.
        [UIView animateWithDuration:1
                         animations:^{
                             subview.alpha = 0;
                         }
                         completion:^(BOOL didComplete){
                             [subview removeFromSuperview];
                             [trashAnimator removeBehavior:push];
                         }];
    }
#pragma mark END
    // Remove the old view
    [self.defaultBehavior removeItem:view];
    [view removeFromSuperview];
}

//爆炸效果的小視圖
- (NSArray *)sliceView:(UIView *)view intoRows:(NSUInteger)rows columns:(NSInteger)columns {
    UIGraphicsBeginImageContext(view.bounds.size);
    [view drawViewHierarchyInRect:view.bounds afterScreenUpdates:YES];
    CGImageRef image = [UIGraphicsGetImageFromCurrentImageContext() CGImage];
    UIGraphicsEndImageContext();
    
    NSMutableArray *views = [NSMutableArray new];
    CGFloat width = CGImageGetWidth(image);
    CGFloat height = CGImageGetHeight(image);
    for (NSUInteger row = 0; row < rows; ++row) {
        for (NSUInteger column = 0; column < columns; ++column) {
           
            CGRect rect = CGRectMake(column * (width / columns),
                                     row * (height / rows),
                                     width / columns,
                                     height / rows);
            CGImageRef subimage = CGImageCreateWithImageInRect(image, rect);
            UIImageView *imageView = [[UIImageView alloc]initWithImage:[UIImage imageWithCGImage:subimage]];
            CGImageRelease(subimage); subimage = NULL;
            
            imageView.frame = CGRectOffset(rect,
                                           CGRectGetMinX(view.frame),
                                           CGRectGetMinY(view.frame));
            [views addObject:imageView];
        }
    }
    
    return views;
}

@end
#import <UIKit/UIKit.h>
#pragma mark 視圖
@interface DraggableView : UIView <NSCopying>
- (instancetype)initWithFrame:(CGRect)frame
                     animator:(UIDynamicAnimator *)animator;
@end

#import "DraggableView.h"

@interface DraggableView ()
@property (nonatomic) UISnapBehavior *snapBehavior;
@property (nonatomic) UIDynamicAnimator *dynamicAnimator;
@property (nonatomic) UIGestureRecognizer *gestureRecognizer;
@end

@implementation DraggableView

- (instancetype)initWithFrame:(CGRect)frame
                     animator:(UIDynamicAnimator *)animator {
  self = [super initWithFrame:frame];
  if (self) {
    _dynamicAnimator = animator;
    self.backgroundColor = [UIColor colorWithRed:arc4random_uniform(255)/255.0 green:arc4random_uniform(255)/255.0 blue:arc4random_uniform(255)/255.0 alpha:1];//隨機背景色

    self.layer.borderWidth = 5;
    self.layer.cornerRadius = 10;
    self.layer.borderColor =[[UIColor colorWithRed:arc4random_uniform(255)/255.0 green:arc4random_uniform(255)/255.0 blue:arc4random_uniform(255)/255.0 alpha:1]CGColor];
    self.gestureRecognizer = [[UIPanGestureRecognizer alloc]
                              initWithTarget:self
                              action:@selector(handlePan:)];
    [self addGestureRecognizer:self.gestureRecognizer];
  }
  return self;
}

- (id)copyWithZone:(NSZone *)zone {
  DraggableView *newView = [[[self class] alloc]
                            initWithFrame:CGRectZero
                            animator:self.dynamicAnimator];
  newView.bounds = self.bounds;
  newView.center = self.center;
  newView.transform = self.transform;
  newView.alpha = self.alpha;
  return newView;
}

- (void)handlePan:(UIPanGestureRecognizer *)g {
    if (g.state == UIGestureRecognizerStateEnded ||
        g.state == UIGestureRecognizerStateCancelled) {
        [self stopDragging];//手勢結束時
    }
    else {
        [self dragToPoint:[g locationInView:self.superview]];//拖曳視圖
    }
}

- (void)dragToPoint:(CGPoint)point {//給手勢添加snap動力學效果
    [self.dynamicAnimator removeBehavior:self.snapBehavior];
    self.snapBehavior = [[UISnapBehavior alloc] initWithItem:self
                                                 snapToPoint:point];
    self.snapBehavior.damping = .25;
    [self.dynamicAnimator addBehavior:self.snapBehavior];
}

- (void)stopDragging {
    [self.dynamicAnimator removeBehavior:self.snapBehavior];
    self.snapBehavior = nil;
}

@end

 

#import <UIKit/UIKit.h>

@class DraggableView;

typedef void(^TearOffHandler)(DraggableView *tornView,
                              DraggableView *newPinView);

#pragma mark 撕裂視圖效果
@interface TearOffBehavior : UIDynamicBehavior
@property(nonatomic) BOOL active;

- (instancetype) initWithDraggableView:(DraggableView *)view
                                anchor:(CGPoint)anchor
                               handler:(TearOffHandler)handler;
@end
#import "TearOffBehavior.h"
#import "DraggableView.h"

@implementation TearOffBehavior

- (instancetype)initWithDraggableView:(DraggableView *)view
                               anchor:(CGPoint)anchor
                              handler:(TearOffHandler)handler {
  self = [super init];
  if (self) {
    _active = YES;

      [self addChildBehavior:[[UISnapBehavior alloc] initWithItem:view
                                                      snapToPoint:anchor]];
      
      CGFloat distance = MIN(CGRectGetWidth(view.bounds),
                             CGRectGetHeight(view.bounds));
      
      TearOffBehavior * __weak weakself = self;
      self.action = ^{//根據手勢拖曳距離 產生新視圖
          
          TearOffBehavior *strongself = weakself;
          
          if (! PointsAreWithinDistance(view.center, anchor, distance)) {
              if (strongself.active) {
                  DraggableView *newView = [view copy];
                  [view.superview addSubview:newView];
                  TearOffBehavior *newTearOff = [[[strongself class] alloc]
                                                 initWithDraggableView:newView
                                                 anchor:anchor
                                                 handler:handler];
                  newTearOff.active = NO;
                  [strongself.dynamicAnimator addBehavior:newTearOff];
                  handler(view, newView);
                  [strongself.dynamicAnimator removeBehavior:strongself];
              }
          }
          else {
              strongself.active = YES;
          }
      };
  }
    return self;
}

/*
 hypoty
 功能:對於給定的直角三角形的兩個直角邊,求其斜邊的長度。
 說明:返回斜邊值。
 */
BOOL PointsAreWithinDistance(CGPoint p1,
                             CGPoint p2,
                             CGFloat distance) {
  CGFloat dx = p1.x - p2.x;
  CGFloat dy = p1.y - p2.y;
  CGFloat currentDistance = hypotf(dx, dy);
  return (currentDistance < distance);
}

@end
#import <UIKit/UIKit.h>
#pragma mark 默認添加 碰撞 重力效果
@interface DefaultBehavior : UIDynamicBehavior
- (void)addItem:(id<UIDynamicItem>)item;
- (void)removeItem:(id<UIDynamicItem>)item;
@end

#import "DefaultBehavior.h"

@implementation DefaultBehavior
//撕裂視圖添加默認動力學行爲
- (instancetype)init {
  self = [super init];
  if (self) {
    UICollisionBehavior *collisionBehavior = [UICollisionBehavior new];
    collisionBehavior.translatesReferenceBoundsIntoBoundary = YES;
    [self addChildBehavior:collisionBehavior];

    UIGravityBehavior *gravityBehavior = [UIGravityBehavior new];
    [self addChildBehavior:gravityBehavior];
  }
  return self;
}

- (void)addItem:(id<UIDynamicItem>)item {
  for (id behavior in self.childBehaviors) {
    [behavior addItem:item];
  }
}

- (void)removeItem:(id<UIDynamicItem>)item {
  for (id behavior in self.childBehaviors) {
    [behavior removeItem:item];
  }
}

@end

(開源中國傳圖200k的限制,也是早晚藥丸)git

https://github.com/zoujie10/UIKitDynamicDemo.gitgithub

相關文章
相關標籤/搜索