iOS开发:仿支付宝界面拖拽按钮动画
来源:互联网 发布:网络教育哪个机构好 编辑:程序博客网 时间:2024/06/09 15:03
两种方式实现模仿支付宝生活界面可拖拽定制方块button的动画效果,当长按方块,可以拖拽方块到新的位置,其他的方块自动移动布局,也可以添加、删除方块。
预览
思路
- 两种动画效果:一种是移动方块时与响铃方块交换位置,另一种是记录索引,方块到达新位置时其他方块依次迁移
- 用到了ios框架的手势识别
- 维持方块内部数据索引与界面布局一致
定义一个方块button类
//// TileView.h// DragTiles//// Created by yxhe on 16/5/26.// Copyright © 2016年 yxhe. All rights reserved.//#import <UIKit/UIKit.h>@class TileButton;@protocol TileButtonDelegate<NSObject>@optional- (void)tileButtonClicked:(TileButton *)tileBtn;@end@interface TileButton : UIButton@property (nonatomic, assign) id<TileButtonDelegate> delegate;@property (nonatomic, assign) NSInteger index; //index in the tile array- (void)setTileText:(NSString *)text clickText:(NSString *)clickText; //set the tile text outside the class- (void)tileLongPressed; //tile longpressed and begin to move, called outside- (void)tileSuspended; //the tile touched pressed but not moved, called outside- (void)tileSettled; //cancel press or settle the tile to new place, called outside@end
//// TileView.m// DragTiles//// Created by yxhe on 16/5/26.// Copyright © 2016年 yxhe. All rights reserved.//#import "TileButton.h"@interface TileButton ()@property (nonatomic, strong) UIButton *deleteButton; //the little del button@end@implementation TileButton- (instancetype)initWithFrame:(CGRect)frame{ self = [super initWithFrame:frame]; if(self) { //set the main button style,in the tile button we can add many things self.backgroundColor = [UIColor yellowColor]; [self setTitleColor:[UIColor redColor] forState:UIControlStateNormal];// [self setTitleColor:[UIColor greenColor] forState:UIControlEventTouchDown]; //add the delete button _deleteButton = [UIButton buttonWithType:UIButtonTypeCustom]; _deleteButton.frame = CGRectMake(self.bounds.size.width*6/7.0, 0, self.frame.size.width/7.0, self.frame.size.height/7.0); //use the relative coordinates _deleteButton.backgroundColor = [UIColor redColor]; _deleteButton.transform = CGAffineTransformMakeScale(0.1, 0.1); //set the deletebutton small at the beginning _deleteButton.hidden = YES; //hide it at the beginning [_deleteButton addTarget:self action:@selector(deleteButtonClicked) forControlEvents:UIControlEventTouchUpInside]; [self addSubview:_deleteButton]; } return self;}#pragma mark - called outside- (void)setTileText:(NSString *)text clickText:(NSString *)clickText{ [self setTitle:text forState:UIControlStateNormal];// [self setTitle:clickText forState:UIControlEventTouchDown]; }- (void)tileLongPressed{ //make the tile half transparent and show the deletebutton [_deleteButton setHidden:NO]; //show the deletebutton [UIView animateWithDuration:0.3 animations:^{ self.alpha = 0.6; self.transform = CGAffineTransformMakeScale(1.1, 1.1); _deleteButton.transform = CGAffineTransformMakeScale(1.0, 1.0); }]; }- (void)tileSuspended{ [_deleteButton setHidden:NO]; [UIView animateWithDuration:0.3 animations:^{ self.alpha = 0.6; self.transform = CGAffineTransformMakeScale(1.0, 1.0); _deleteButton.transform = CGAffineTransformMakeScale(1.0, 1.0); }];}- (void)tileSettled{ [UIView animateWithDuration:0.3 animations:^{ self.alpha = 1.0; self.transform = CGAffineTransformMakeScale(1.0, 1.0); _deleteButton.transform = CGAffineTransformMakeScale(0.1, 0.1); }]; [self performSelector:@selector(delayHide) withObject:nil afterDelay:0.3];}- (void)delayHide{ [_deleteButton setHidden:YES]; //the main button removed then the deletebutton automatically removed}#pragma button callback- (void)deleteButtonClicked{ NSLog(@"delete button clicked"); if([self.delegate respondsToSelector:@selector(tileButtonClicked:)]) [self.delegate tileButtonClicked:self]; }@end在这个button类里面封装一些内容,比如处理手势长按和取消的函数,响应删除的委托事件回调(其实也可以用发送消息来做),还有button被长按后悬浮的放大透明动画,以及delete按钮缩放的动画。
主界面里面对手势的处理
- (void)onLongGresture:(UILongPressGestureRecognizer *)sender{#ifndef ALIPAY_ANIMATION [self handleFreeMove:sender];#else [self handleSequenceMove:sender];#endif}
动画一
//method 1: exchange the adjacent tiles, the sequence of the array elements will be disorderd- (void)handleFreeMove:(UILongPressGestureRecognizer *)sender{ TileButton *tile_btn = sender.view; //get the dragged tilebutton switch(sender.state) { case UIGestureRecognizerStateBegan: startPos = [sender locationInView:sender.view]; originPos = tile_btn.center; [tile_btn tileSuspended]; touchState = SUSPEND; preTouchID = tile_btn.index; //save the ID of pretouched title break; case UIGestureRecognizerStateChanged: { [tile_btn tileLongPressed]; touchState = MOVE; //the tile will move CGPoint newPoint = [sender locationInView:sender.view]; CGFloat offsetX = newPoint.x - startPos.x; CGFloat offsetY = newPoint.y - startPos.y; tile_btn.center = CGPointMake(tile_btn.center.x + offsetX, tile_btn.center.y + offsetY); //get the intersect tile ID int intersectID = -1; for(NSInteger i = 0; i < _tileArray.count; i++) if(tile_btn != _tileArray[i] && CGRectContainsPoint([_tileArray[i] frame], tile_btn.center)) { intersectID = i; break; } if(intersectID != -1) { //swap every tile, the index remains unchanged __block TileButton *collisionButton = _tileArray[intersectID]; __block CGPoint tempOriginPos = collisionButton.center; //the new origin point [UIView animateWithDuration:0.3 animations:^{ collisionButton.center = originPos; //move the other title to the moved tile's origin pos originPos = tempOriginPos; //save the temp origin point in case the block shake }]; //exchange the tile index of the array [_tileArray exchangeObjectAtIndex:tile_btn.index withObjectAtIndex:intersectID]; //tile_btn still point to the moving tile, just swap the index int tempID = collisionButton.index; collisionButton.index = tile_btn.index; tile_btn.index = tempID; } } break; case UIGestureRecognizerStateEnded: { // [tile_btn tileSuspended]; [UIView animateWithDuration:0.3 animations:^{ tile_btn.center = originPos; }]; if(touchState == MOVE) //only if the pre state is MOVE, then settle, otherwise leave it suspend { touchState = UNTOUCHED; [tile_btn tileSettled]; //settle the tile to the new position(no need to use delay operation here) } } break; default: break; }}定义一个状态枚举,当长按手势处于不同的状态时进行状态转换,基本原理是,拖动方块过程中不断记录坐标位置,实现相邻方块交换位置。
动画二
//method 2: move the tiles inorder like Alipay, the order in array remains in sequence always- (void)handleSequenceMove:(UILongPressGestureRecognizer *)sender{ TileButton *tile_btn = sender.view; //get the dragged tilebutton switch(sender.state) { case UIGestureRecognizerStateBegan: startPos = [sender locationInView:sender.view]; originPos = tile_btn.center; [tile_btn tileSuspended]; touchState = SUSPEND; preTouchID = tile_btn.index; //save the ID of pretouched title break; case UIGestureRecognizerStateChanged: { [tile_btn tileLongPressed]; touchState = MOVE; //the tile will move CGPoint newPoint = [sender locationInView:sender.view]; CGFloat offsetX = newPoint.x - startPos.x; CGFloat offsetY = newPoint.y - startPos.y; tile_btn.center = CGPointMake(tile_btn.center.x + offsetX, tile_btn.center.y + offsetY); //get the intersect tile ID int intersectID = -1; for(NSInteger i = 0; i < _tileArray.count; i++) if(tile_btn != _tileArray[i] && CGRectContainsPoint([_tileArray[i] frame], tile_btn.center)) { intersectID = i; break; } if(intersectID != -1) { if(abs(intersectID - tile_btn.index) == 1) //if the tiles are adjacent then move directly { __block TileButton *collisionButton = _tileArray[intersectID]; __block CGPoint tempOriginPos = collisionButton.center; //the new origin point [UIView animateWithDuration:0.3 animations:^{ collisionButton.center = originPos; //move the other title to the moved tile's origin pos originPos = tempOriginPos; //save the temp origin point in case the block shake }]; //exchange the tile index of the array [_tileArray exchangeObjectAtIndex:tile_btn.index withObjectAtIndex:intersectID]; //tile_btn still point to the moving tile, just swap the index int tempID = collisionButton.index; collisionButton.index = tile_btn.index; tile_btn.index = tempID; NSLog(@"tilebtn index:%d, intersect index:%d", [_tileArray[tile_btn.index] index], [_tileArray[collisionButton.index] index]); } else if(intersectID - tile_btn.index >1) //move the tiles to the left in order { CGPoint preCenter = originPos; CGPoint curCenter; //exchange the pointer in array and swap the index,at last the tile_btn is at the new right place for(int i = tile_btn.index + 1; i <= intersectID; i++) { __block TileButton *movedTileBtn = _tileArray[i]; curCenter = movedTileBtn.center; [UIView animateWithDuration:0.3 animations:^{ movedTileBtn.center = preCenter; }]; preCenter = curCenter; //save the precenter movedTileBtn.index--; //reduce the tile index _tileArray[i-1] = movedTileBtn; //move the pointer one by one } originPos = preCenter; tile_btn.index = intersectID; //exchange the ID _tileArray[intersectID] = tile_btn; //now make the last pointer point to the tile_btn NSLog(@"new tile btn index: %d", [_tileArray[tile_btn.index] index]); } else //move the tile to right in order { CGPoint preCenter = originPos; CGPoint curCenter; //exchange the pointer in array and swap the index,at last the tile_btn is at the new right place for(int i = tile_btn.index - 1; i >= intersectID; i--) { __block TileButton *movedTileBtn = _tileArray[i]; curCenter = movedTileBtn.center; [UIView animateWithDuration:0.3 animations:^{ movedTileBtn.center = preCenter; }]; preCenter = curCenter; //save the precenter movedTileBtn.index++; //reduce the tile index _tileArray[i+1] = movedTileBtn; //move the pointer one by one } originPos = preCenter; tile_btn.index = intersectID; //exchange the ID _tileArray[intersectID] = tile_btn; //now make the last pointer point to the tile_btn NSLog(@"new tile btn index: %d", [_tileArray[tile_btn.index] index]); } //test the display if the array is inorder for(TileButton *tile in _tileArray) NSLog(@"tile text: %@", tile.titleLabel.text); } } break; case UIGestureRecognizerStateEnded: { // [tile_btn tileSuspended]; [UIView animateWithDuration:0.3 animations:^{ tile_btn.center = originPos; }]; if(touchState == MOVE) //only if the pre state is MOVE, then settle, otherwise leave it suspend [tile_btn tileSettled]; //settle the tile to the new position(no need to use delay operation here) } break; default: break; }}这种动画的区别在于,方块移动到新的位置,别的方块自动依次按顺序补齐之前的空位置,基本原理是,保存方块索引,以及起始位置和终止位置,方块按顺序移动。
删除动画
//tile delete button clicked- (void)tileButtonClicked:(TileButton *)tileBtn{ //remove the button and adjust the tilearray NSLog(@"deletebutton delegate responds"); //remember the deleted tile's infomation int startIndex = tileBtn.index; CGPoint preCenter = tileBtn.center; CGPoint curCenter; //[_tileArray removeObject:tileBtn]; //delete the tile //exchange the pointer in array and swap the index,at last the tile_btn is at the new right place for(int i = startIndex + 1; i < _tileArray.count; i++) { __block TileButton *movedTileBtn = _tileArray[i]; curCenter = movedTileBtn.center; [UIView animateWithDuration:0.3 animations:^{ movedTileBtn.center = preCenter; }]; preCenter = curCenter; //save the precenter movedTileBtn.index--; //reduce the tile index _tileArray[i-1] = movedTileBtn; //move the pointer one by one } [_tileArray removeLastObject]; //every time remove the last object //must remove the tileBtn from the view [tileBtn removeFromSuperview]; //we can also use performselector so that button disappears with animation //test the display if the array is inorder for(TileButton *tile in _tileArray) NSLog(@"tile text: %@", tile.titleLabel.text);}当删除某个方块时,后面的方块也会自动补齐,有个动画效果。
源代码下载
csdn:仿支付宝拖拽方块
github:DragTiles
0 0
- iOS开发:仿支付宝界面拖拽按钮动画
- 仿支付宝口碑按钮动画
- iOS核心动画实现仿支付宝咻咻、雷达效果
- Android仿支付宝支付验证按钮
- 仿支付宝支付成功动画
- PathMeasure 仿支付宝支付动画
- IOS支付界面锁定按钮,防止支付第二次
- 仿支付宝输入密码界面
- 仿支付宝“数字增长动画”
- 高仿支付宝首页头部动画
- 仿支付宝输入支付密码2(带动画)
- Android开发笔记(一百四十四)高仿支付宝的头部伸缩动画
- iOS支付宝 界面定制
- ios支付宝支付开发
- iOS开发-支付宝支付
- IOS开发--支付宝支付
- iOS开发支付宝支付
- iOS 支付宝支付开发
- poj1655(树的重心)
- abc
- GDAL 2.1.0工具开发之gdal_translate(图像裁剪、缩放、拉伸、赋坐标投影、格式转换等)
- 安卓学习
- 总结替换jar包中指定文件的步骤
- iOS开发:仿支付宝界面拖拽按钮动画
- 分分钟解决iOS开发中App启动广告的功能
- java 原型模式
- abc
- Python 解析配置模块之ConfigParser详解
- 设计一个通用的BaseActivity
- Fresco的缓存机制
- abc
- 关于JavaScript中的delete