四. 关键处理– 你离成功不远了
好了,我们终于要处理用户的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];
}