iOS 支付寶首頁拖放按鈕效果實現

jopen 9年前發布 | 3K 次閱讀 Objective-C 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 自行上傳分享,僅供網友學習交流。所有權歸原作者,若您的權利被侵害,請聯系管理員。
 轉載本站原創文章,請注明出處,并保留原始鏈接、圖片水印。
 本站是一個以用戶分享為主的開源技術平臺,歡迎各類分享!