#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