天天看点

在iOS上实现Cover Flow (四)

四. 关键处理– 你离成功不远了

好了,我们终于要处理用户的pan手势了,这非常简单:

- (void) handlePanFrom:(UIPanGestureRecognizer*)recognizer
{
    if (recognizer.state == UIGestureRecognizerStateChanged) {
        // 获得相对位移
        CGPoint translation = [recognizer translationInView:recognizer.view];
        if (abs(translation.x) > 100) {     // 相对位移超过一定的值则移动图片
            
            // 根据方向移动image
BOOL isLeft = (translation.x > 0) ? NO : YES;
// 向左或向右移动一步(更换image)
            [self moveOneStep:isLeft];
            
            [recognizer setTranslation:CGPointZero inView:recognizer.view];
        }
    }
}
           

       上述的代码中,关于recognizer的处理不是本文的重点,我们现在把注意力放在moveOneStep:方法上。它可以说是本教程中最为关键,也是逻辑最容易出错的地方。moveOneStep:的具体实现如下:

// 向左或向右移动一步(更换image)
- (void) moveOneStep:(BOOL)isLeft
{   
    // 到达第一张或最后一张时,禁止移动
    if ((_curImageIndex == 0                    && !isLeft) || 
        (_curImageIndex == _arrImages.count-1   && isLeft)) {
        return;
    }

    // 根据向左还是向右进行下标偏移
    int di = isLeft ? -1 : 1;
    // 计算对应在模板layer的起始下标
    int targetIndex = (_curImageIndex < _SIDEPIECES) ? (_SIDEPIECES+1-_curImageIndex+di) : (1+di);
    for (int i=0; i<_arrLayers.count; i++) {
        CALayer *originLayer = (CALayer*)[_arrLayers objectAtIndex:i];
        CALayer *targetLayer = (CALayer*)[_arrTempleteLayers objectAtIndex:i+targetIndex];
        
        [CATransaction setAnimationDuration:1];
        originLayer.position = targetLayer.position;
        originLayer.zPosition = targetLayer.zPosition;
        originLayer.transform = targetLayer.transform;
        // 设置originLayer的bounds
        CGFloat scale = 1.0f;
        if (i + targetIndex - 1 == _SIDEPIECES) {
            scale = _MIDDLESCALE / _SIDESCALE;
        } else if (((i + targetIndex - 1 == _SIDEPIECES - 1) && isLeft) ||
                   ((i + targetIndex - 1 == _SIDEPIECES + 1) && !isLeft)) {
            scale = _SIDESCALE / _MIDDLESCALE;
        }
        [self scaleBounds:originLayer x:scale y:scale];
        // 设置originLayer的reflection的bounds
        CALayer *reflectLayer = (CALayer*)[originLayer.sublayers objectAtIndex:0];
        [self scaleBounds:reflectLayer x:scale y:scale];
        // 设置originLayer的reflection的mask的bounds
        [self scaleBounds:reflectLayer.mask x:scale y:scale];
        // 设置originLayer的reflection的sublayer的bounds
        [self scaleBounds:(CALayer*)[reflectLayer.sublayers objectAtIndex:0] x:scale y:scale];
        // 矫正reflection的position
        reflectLayer.position = CGPointMake(originLayer.bounds.size.width/2, originLayer.bounds.size.height*1.5);
        // 矫正reflection的mask的position
        reflectLayer.mask.position = CGPointMake(reflectLayer.bounds.size.width/2, reflectLayer.bounds.size.height/2);
        // 矫正reflection的sublayer的position
        ((CALayer*)[reflectLayer.sublayers objectAtIndex:0]).position = CGPointMake(reflectLayer.bounds.size.width/2, reflectLayer.bounds.size.height/2);
    }
    
    // 下面根据向左或向右,对当前显示的image(layer)进行添加或者删除
    // <- 如果是向左,那么可能需要移除最左侧的layer,并可能需要在最右侧添加新layer
    if (isLeft) {
// 向左或向右移动一步(更换image)
- (void) moveOneStep:(BOOL)isLeft
{   
    // 到达第一张或最后一张时,禁止移动
    if ((_curImageIndex == 0                    && !isLeft) || 
        (_curImageIndex == _arrImages.count-1   && isLeft)) {
        return;
    }

    // 根据向左还是向右进行下标偏移
    int di = isLeft ? -1 : 1;
    // 计算对应在模板layer的起始下标
    int targetIndex = (_curImageIndex < _SIDEPIECES) ? (_SIDEPIECES+1-_curImageIndex+di) : (1+di);
    for (int i=0; i<_arrLayers.count; i++) {
        CALayer *originLayer = (CALayer*)[_arrLayers objectAtIndex:i];
        CALayer *targetLayer = (CALayer*)[_arrTempleteLayers objectAtIndex:i+targetIndex];
        
        [CATransaction setAnimationDuration:1];
        originLayer.position = targetLayer.position;
        originLayer.zPosition = targetLayer.zPosition;
        originLayer.transform = targetLayer.transform;
        // 设置originLayer的bounds
        CGFloat scale = 1.0f;
        if (i + targetIndex - 1 == _SIDEPIECES) {
            scale = _MIDDLESCALE / _SIDESCALE;
        } else if (((i + targetIndex - 1 == _SIDEPIECES - 1) && isLeft) ||
                   ((i + targetIndex - 1 == _SIDEPIECES + 1) && !isLeft)) {
            scale = _SIDESCALE / _MIDDLESCALE;
        }
        [self scaleBounds:originLayer x:scale y:scale];
        // 设置originLayer的reflection的bounds
        CALayer *reflectLayer = (CALayer*)[originLayer.sublayers objectAtIndex:0];
        [self scaleBounds:reflectLayer x:scale y:scale];
        // 设置originLayer的reflection的mask的bounds
        [self scaleBounds:reflectLayer.mask x:scale y:scale];
        // 设置originLayer的reflection的sublayer的bounds
        [self scaleBounds:(CALayer*)[reflectLayer.sublayers objectAtIndex:0] x:scale y:scale];
        // 矫正reflection的position
        reflectLayer.position = CGPointMake(originLayer.bounds.size.width/2, originLayer.bounds.size.height*1.5);
        // 矫正reflection的mask的position
        reflectLayer.mask.position = CGPointMake(reflectLayer.bounds.size.width/2, reflectLayer.bounds.size.height/2);
        // 矫正reflection的sublayer的position
        ((CALayer*)[reflectLayer.sublayers objectAtIndex:0]).position = CGPointMake(reflectLayer.bounds.size.width/2, reflectLayer.bounds.size.height/2);
    }
    
    // 下面根据向左或向右,对当前显示的image(layer)进行添加或者删除
    // <- 如果是向左,那么可能需要移除最左侧的layer,并可能需要在最右侧添加新layer
    if (isLeft) {
        // 需要移除最左侧的layer
        if (_curImageIndex >= _SIDEPIECES) {
            CALayer *removeLayer = (CALayer*)[_arrLayers objectAtIndex:0];
            [_arrLayers removeObject:removeLayer];
            [self performSelector:@selector(removeLayerAfterSeconds:) withObject:removeLayer afterDelay:1];
        }
        // 在最右侧添加新layer
        int num = _arrImages.count - _SIDEPIECES - 1;
        if (_curImageIndex < num) {
            UIImage *aImage = (UIImage*)[_arrImages objectAtIndex:_curImageIndex+_SIDEPIECES+1];
            CALayer *newLayer = [CALayer layer];
            newLayer.contents = (id)aImage.CGImage;
            CGFloat scale = _SIDESCALE;
            newLayer.bounds = CGRectMake(0, 0, aImage.size.width*scale, aImage.size.height*scale);
            [self._arrLayers addObject:newLayer];
            
            CALayer *targetLayer = (CALayer*)[_arrTempleteLayers objectAtIndex:_arrTempleteLayers.count-2];
            newLayer.position = targetLayer.position;
            newLayer.zPosition = targetLayer.zPosition;
            newLayer.transform = targetLayer.transform;
            // 显示layer
            [self showImageAndReflection:newLayer];
        }
    }
    // -> 如果是向右,那么可能需要移除最右侧的layer,并可能需要在最左侧添加新layer
    else {
        // 需要移除最右侧的layer
        int num = _arrImages.count - _SIDEPIECES - 1;
        if (_curImageIndex <= num) {
            CALayer *removeLayer = (CALayer*)[_arrLayers lastObject];
            [_arrLayers removeObject:removeLayer];
            [self performSelector:@selector(removeLayerAfterSeconds:) withObject:removeLayer afterDelay:1];
        }
        // 在最左侧添加新layer
        if (_curImageIndex > _SIDEPIECES) {
            UIImage *aImage = (UIImage*)[_arrImages objectAtIndex:_curImageIndex-_SIDEPIECES-1];
            CALayer *newLayer = [CALayer layer];
            newLayer.contents = (id)aImage.CGImage;
            CGFloat scale = _SIDESCALE;
            newLayer.bounds = CGRectMake(0, 0, aImage.size.width*scale, aImage.size.height*scale);
            [self._arrLayers insertObject:newLayer atIndex:0];
            
            CALayer *targetLayer = (CALayer*)[_arrTempleteLayers objectAtIndex:1];
            newLayer.position = targetLayer.position;
            newLayer.zPosition = targetLayer.zPosition;
            newLayer.transform = targetLayer.transform;
            // 显示layer
            [self showImageAndReflection:newLayer];
        }
    }
    
    // 更新当前显示在正中心的image的下标
    _curImageIndex = isLeft ? _curImageIndex+1 :  _curImageIndex-1;
    
    // 更新pageControl
    _pageControl.currentPage = _curImageIndex;
}
           

       同样,代码中的注释已经很清楚地说明了每一个步骤所做的工作,这里就不加复述。需要注意的地方是向左或向右滑动后,可能要对layer进行删除或添加,这部分的逻辑处理你需要仔细体会。

       绝大部分的工作都完成啦,这意味着马上可以进入尾声了。不过你发现moveOneStep:方法中调用的几个方法还未给出,好的,它们就在下面:

// 移除原有的sublayer
- (void)removeSublayers
{
    for (CALayer *layer in self._arrLayers) {
        [layer removeFromSuperlayer];
    }
}

// 清空_arrLayers数组
- (void)cleanLayersArray
{
    [_arrLayers removeAllObjects];
}

// 对bounds进行尺寸调整
- (void)scaleBounds:(CALayer*)layer x:(CGFloat)scaleWidth y:(CGFloat)scaleHeight
{
    layer.bounds = CGRectMake(0, 0, layer.bounds.size.width*scaleWidth, layer.bounds.size.height*scaleHeight);
}

// 移除指定的sublayer(在delay一定时间后)
- (void)removeLayerAfterSeconds:(id)removeLayer
{
    removeLayer = (CALayer*)removeLayer;
    [removeLayer removeFromSuperlayer];
}