iOS 卡片拖拽+翻转效果 。 仿tableview从缓存池中获取cell机制

1.效果图如下:

 

 

1.拖拽时分三种状态:

  

- (void)panOfRemoveMode:(UIPanGestureRecognizer *)gesture
{
    if (gesture.state == UIGestureRecognizerStateBegan) {

        // 初始手指滑动的距离
        __fingerPoiX = 0;
        // 当前项
        __curItem = self.visiableItems[0];
        // 上一项
        __lastItem = __visibleIndex > 0 ? [self itemAtIndex:__visibleIndex - 1] : nil;
        
        if (__lastItem) {
            
            // 先添加上并设置初始位置
            [__lastItem removeAlphaMaskView];
            [self addSubview:__lastItem];
            [self setFinalFrameForItem:__lastItem atIndex:-1 isUpdate:NO isLeftFinal:YES];
            [self setTransformForItem:__lastItem atIndex:0];
        }
    }
    else if (gesture.state == UIGestureRecognizerStateChanged) {
        
        CGPoint movedPoint = [gesture translationInView:self];
        
        __fingerPoiX += movedPoint.x;
        
        // 避免一个手势左右滑动,即操作了 curItem,又操作了 lastItem
        if (__fingerPoiX < 0 && __lastItem) {
            [__lastItem removeFromSuperview];
            __lastItem = nil;
        }
        
        // 左滑且未至底端
        if (__fingerPoiX < 0 && __visibleIndex < [self numberOfItems] - 1) {
            
            [self calculateItemCenter:__curItem point:movedPoint isDeleteMode:NO];
            [self adjustTranslateAngle:__curItem centerX:__curItem.center.x];
        }
        // 右滑且未至顶端
        else if (__fingerPoiX > 0 && __visibleIndex > 0 && __lastItem) {
            
            [self calculateItemCenter:__lastItem point:movedPoint isDeleteMode:NO];
            [self adjustTranslateAngle:__lastItem centerX:__lastItem.center.x];
        }
        
        [gesture setTranslation:CGPointZero inView:self];
        
    }
    else if (gesture.state == UIGestureRecognizerStateEnded) {
        
        CGPoint vel = [gesture velocityInView:self];
        
        if (__fingerPoiX < 0 && __visibleIndex < [self numberOfItems] - 1) {  // 左滑
        
            if (vel.x < -800) {
                [self cardItemOutOfScreenEndScrollAnimation:__curItem isLeftFinal:YES isFast:YES];
            }
            else if(__fingerPoiX < -100){
                [self cardItemOutOfScreenEndScrollAnimation:__curItem isLeftFinal:YES isFast:NO];
            }
            else {
                [self cardItemToOriginalEndScrollAnimation:__curItem isFast:NO];
            }
        }
        else if (__lastItem && __fingerPoiX > 0){  // 右滑
            
            if(vel.x > 800) {
                [self cardItemToOriginalEndScrollAnimation:__lastItem isFast:YES];
            }
            else if (__fingerPoiX > CARDITEM_RIGHT_RESPONDLENGTH){
                [self cardItemToOriginalEndScrollAnimation:__lastItem isFast:NO];
            }
            else {
                [self cardItemOutOfScreenEndScrollAnimation:__lastItem isLeftFinal:YES isFast:NO];
            }
        }
        else {
            // 只对当前可视视图进行纠错
            [self cardItemToOriginalEndScrollAnimation:__curItem isFast:NO];
        }
    }
}

 

/**
  *  @brief   设置卡片项的放射变换
  */
- (void)setTransformForItem:(CardViewItem *)item atIndex:(NSInteger)idx
{
    CGAffineTransform scale = CGAffineTransformMakeScale(1 - self.scaleRatio * idx, 1);
    item.transform = CGAffineTransformTranslate(scale, 0, 15 * idx);
}

 

/**
  *  @brief   设置卡片项的最终位置约束
  *  @param   idx   索引,用于新添加 item 还未设置 frame 时添加约束
  *  @param   isUpdate   是否是更新约束
  *  @param   isLeft   yes - 最终位置在左侧    no - 最终位置在右侧
  */
- (void)setFinalFrameForItem:(CardViewItem *)item atIndex:(NSInteger)idx isUpdate:(BOOL)isUpdate isLeftFinal:(BOOL)isLeft
{
    // cx 代表 item.center.x; centerX 代表 item 与 self 中心点的距离
    NSInteger cx = -300;
    NSInteger centerX = cx - self.center.x;
    
    // 如图:|← 300 →□← 300 →|( | 代表 item.center.x 位置, 300 代表距离,□ 代表self 视图)
    if (!isLeft) {
        cx = -cx + W(self);    centerX = -centerX;
    }
    
    if (isUpdate) {
    
        // 设置旋转角度
        [self adjustTranslateAngle:item centerX:cx];
        item.center = CGPointMake(cx, H(self)/2 + 100);
    
        [item mas_updateConstraints:^(MASConstraintMaker * make) {
            make.centerX.equalTo(@(centerX));
            make.centerY.equalTo(@(100));
        }];
    }
    else {
        CGRect rect = [self itemRectAtIndex:idx];
        item.center = CGPointMake(cx, H(self)/2 + 100);

        [item mas_makeConstraints:^(MASConstraintMaker * make) {
            make.centerX.equalTo(@(centerX));
            make.centerY.equalTo(@(100));
            make.width.equalTo(@(rect.size.width));
            make.height.equalTo(@(rect.size.height));
        }];
    }
}

 

/**
  *  @brief   设置卡片项的初始位置约束
  *  @attention   item 缩放时其子视图也缩小;还原时,如果 item 与父视图没有约束,则 item 的子视图不会还原且在滑动时界面出错
  */
- (void)setOriginalFrameForItem:(CardViewItem *)item atIndex:(NSInteger)idx isUpdate:(BOOL)isUpdate
{
    SELF_WEAK;
    if (isUpdate) {
        
        // 约束不会导致 frame 调整
        item.center = CGPointMake(W(self)/2, H(item)/2);
        item.transform = CGAffineTransformMakeRotation(0);

        [item mas_updateConstraints:^(MASConstraintMaker * make) {
            SELF_STRONG;
            make.centerX.equalTo(strongSelf);
            make.centerY.equalTo(@((H(item) - H(strongSelf))/2 ));
        }];
    }
    else {
        CGRect rect = [self itemRectAtIndex:idx];
        item.center = CGPointMake(W(self) / 2, rect.size.height / 2);

        [item mas_makeConstraints:^(MASConstraintMaker * make) {
            SELF_STRONG;
            make.centerX.equalTo(strongSelf);
            make.centerY.equalTo(@((rect.size.height - H(strongSelf)) /2 ));
            make.width.equalTo(@(rect.size.width));
            make.height.equalTo(@(rect.size.height));
        }];
    }
}

 

/**
  *  @brief   从复用项数组中获取可复用对象,没有则新创建 。仿tableview的cell重用机制
  */
- (CardViewItem *)dequeueReusableCellWithIdentifier:(NSString *)identifier
{
    __block CardViewItem * item = nil;
    
    // 有可复用项 + 剩余的项 > _maxItems
    if (self.reusableItems.count > 0 && __visibleIndex <= [self numberOfItems] - self.maxItems) {
        
        [self.reusableItems enumerateObjectsUsingBlock:^(CardViewItem * obj, NSUInteger idx, BOOL * stop) {
            
            if ([obj.reuseIdentifier isEqualToString:identifier]) {
            
                item = obj;
                *stop = YES;
            }
        }];
    }
    else {
        
        [self.mapDict enumerateKeysAndObjectsUsingBlock:^(NSString * key, id obj, BOOL * stop) {
            
            if ([key isEqualToString:identifier]) {
                
                if ([obj isKindOfClass:[NSString class]]) {   // xib 文件
                
                    item = (CardViewItem *)[self viewFromXibFile:(NSString *)obj];
                }
                else {  // 类文件
                    item = [[(Class)obj alloc] init];
                }
                item.reuseIdentifier = key;
                
                [item addGestureRecognizer:[[UITapGestureRecognizer alloc] initWithTarget:self
                                                                        action:@selector(tap:)]];

                *stop = YES;
            }
        }];
    }
    return item;
}

 

转载于:https://www.cnblogs.com/onlyMyRailGun/p/6380513.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值