iOS 支付寶首頁拖放按鈕效果實現
效果圖:
1.實現原理
將所有按鈕放在viewcontroller的_buttonArray集合中,同時賦值給按鈕中
增加長按手勢的響應
當手勢坐標進入其他按鈕的frame時,調整集合中按鈕位置;
當長按手勢開始,放大按鈕; 結束時還原按鈕
2.附源碼及注釋[按鈕調控已實現動畫]
@interface UIDragButton : UIButton { CGPoint _prePoint; // 移動過程中的上一個點 BOOL _isPress; // 是否按下:實現過程未用到 CGPoint _framePoint; // 未放大情況下frame的左上角坐標 CGRect _frameRect; // 未放大情況下frame值 } @property (nonatomic, assign) NSMutableArray *buttonArray; // button集合 @property (nonatomic, assign) NSInteger indexOfArray; // 當前按鈕在集合中的下標 // 移動動畫,實現過程未用到,暫不能用 - (void)moveTo:(CGRect)rect Animation:(BOOL)flag; // 初始化一些樣式,即長按手勢 - (void)initStyle; @end
.m
@implementation UIDragButton /* * 樣式初始化,即手勢初始化 **/ - (void)initStyle { self.backgroundColor = [UIColor whiteColor]; self.layer.borderWidth = 0.3; self.layer.borderColor = [UIColor grayColor].CGColor; UILongPressGestureRecognizer * longPressGr = [[UILongPressGestureRecognizer alloc] initWithTarget:self action:@selector(longPressToDo:)]; longPressGr.minimumPressDuration = 1.0; [self addGestureRecognizer:longPressGr]; } #pragma mark - 按鈕尺寸更改 // 放大 - (void)changeBig { self.transform = CGAffineTransformScale(self.transform,1.25,1.25); self.backgroundColor = [UIColor colorWithHexString:@"E0E0E0" alpha:1]; } // 還原 - (void)changeBack { self.transform = CGAffineTransformScale(self.transform,0.8,0.8); // 按鈕放大還原后會有偏移,所以要設置回正常位置,80和100是按鈕尺寸 self.frame = CGRectMake(_framePoint.x, _framePoint.y, 80, 100); } #pragma mark - 手勢管理 /* * 手勢響應,并判斷狀態 **/ - (void)longPressToDo:(UILongPressGestureRecognizer *)press { if ([press state] == UIGestureRecognizerStateBegan) { [self beganTouch:press]; [self changeBig]; // 放大 } else if ([press state] == UIGestureRecognizerStateChanged) { [self movedTouch:press]; } else if ([press state] == UIGestureRecognizerStateEnded){ [self endedTouch:press]; } } /* * 手勢長按開始 **/ - (void)beganTouch:(UILongPressGestureRecognizer *)press { _prePoint = [press locationInView:self]; _frameRect = self.frame; _framePoint = self.frame.origin; // 該通知用于告訴controller點擊的是第幾個按鈕,用于將該按鈕放在最上層 [[NSNotificationCenter defaultCenter] postNotificationName:@"buttonChanged" object:[NSNumber numberWithInteger:_indexOfArray]]; } /* * 手勢長按結束 **/ - (void)endedTouch:(UILongPressGestureRecognizer *)press { _prePoint = [press locationInView:self]; [self changeBack]; self.backgroundColor = [UIColor whiteColor]; } /* * 長按過程中移動 **/ - (void)movedTouch:(UILongPressGestureRecognizer *)press { CGPoint now = [press locationInView:self]; NSInteger x = now.x - _prePoint.x; NSInteger y = now.y - _prePoint.y; self.frame = CGRectMake(self.frame.origin.x+x, self.frame.origin.y+y, self.frame.size.width, self.frame.size.height); [self placeIsChanged:CGPointMake(self.frame.origin.x + _prePoint.x, self.frame.origin.y + _prePoint.y)]; } #pragma mark - 按鈕調整 /* * 判斷當前按鈕位置是否變化,并進行調整 **/ - (void)placeIsChanged:(CGPoint)point { for (NSInteger i = 0; i < [self.buttonArray count]; i++) { if ([self pointIn:point rect:((UIButton *)[_buttonArray objectAtIndex:i]).frame] && _indexOfArray != i) { [self adjustButtons:i]; } } } /* * 判斷點是否在rect內 **/ - (BOOL)pointIn:(CGPoint)point rect:(CGRect)rect { if (point.x > rect.origin.x && point.y > rect.origin.y && point.x < rect.origin.x+rect.size.width && point.y < rect.origin.y+rect.size.height) { return YES; } return NO; } /* * 調整按鈕位置 **/ - (void)adjustButtons:(NSInteger)index { CGRect rect = ((UIButton *)[_buttonArray objectAtIndex:index]).frame; __block NSInteger i = 0; __block NSInteger num = index; // 將靠前的按鈕移動到靠后的位置 if (_indexOfArray < index) { // 將上一個按鈕的位置賦值給當前按鈕 [UIView animateWithDuration:0.5 animations:^{ for (i = num; i > _indexOfArray+1; i--) { ((UIDragButton *)[_buttonArray objectAtIndex:i]).frame = ((UIDragButton *)[_buttonArray objectAtIndex:i-1]).frame; } ((UIDragButton *)[_buttonArray objectAtIndex:i]).frame = _frameRect; }]; _frameRect = rect; // 調整順序 保證數組中按鈕的frame按順序排列 for (i = _indexOfArray; i < index; i++) { [_buttonArray exchangeObjectAtIndex:i withObjectAtIndex:i+1]; ((UIDragButton *)[_buttonArray objectAtIndex:i]).indexOfArray = i; } ((UIDragButton *)[_buttonArray objectAtIndex:index]).indexOfArray = index; } else { // 將靠后的按鈕移動到前邊 // 將上一個按鈕的位置賦值給當前按鈕 [UIView animateWithDuration:0.5 animations:^{ for (i = num; i < _indexOfArray-1; i++) { ((UIDragButton *)[_buttonArray objectAtIndex:i]).frame = ((UIDragButton *)[_buttonArray objectAtIndex:i+1]).frame; } ((UIDragButton *)[_buttonArray objectAtIndex:i]).frame = _frameRect; }]; _frameRect = rect; // 調整順序 保證數組中按鈕的frame按順序排列 for (i = _indexOfArray; i > index; i--) { [_buttonArray exchangeObjectAtIndex:i withObjectAtIndex:i-1]; ((UIDragButton *)[_buttonArray objectAtIndex:i]).indexOfArray = i; } ((UIDragButton *)[_buttonArray objectAtIndex:index]).indexOfArray = index; } _framePoint = _frameRect.origin; } #pragma mark - 按鈕移動動畫 - (void)moveTo:(CGRect)rect Animation:(BOOL)flag { if (flag) { // 計算偏移并移動 float x = rect.origin.x - self.frame.origin.x; float y = rect.origin.y - self.frame.origin.y; [self.layer addAnimation:[self moveX:0.1 X:[NSNumber numberWithFloat:x]] forKey:nil]; [self.layer addAnimation:[self moveY:0.1 Y:[NSNumber numberWithFloat:y]] forKey:nil]; } else { self.frame = rect; } } - (CABasicAnimation *)moveX:(float)time X:(NSNumber *)x // 橫向移動 { CABasicAnimation *animation=[CABasicAnimation animationWithKeyPath:@"transform.translation.x"]; animation.toValue=x; animation.duration=time; // 動畫持續時間 animation.removedOnCompletion=NO; animation.fillMode=kCAFillModeForwards; return animation; } - (CABasicAnimation *)moveY:(float)time Y:(NSNumber *)y // 縱向移動 { CABasicAnimation *animation=[CABasicAnimation animationWithKeyPath:@"transform.translation.y"]; animation.toValue=y; animation.duration=time; animation.removedOnCompletion=NO; animation.fillMode=kCAFillModeForwards; return animation; } @end
本文由用戶 jopen 自行上傳分享,僅供網友學習交流。所有權歸原作者,若您的權利被侵害,請聯系管理員。
轉載本站原創文章,請注明出處,并保留原始鏈接、圖片水印。
本站是一個以用戶分享為主的開源技術平臺,歡迎各類分享!