OurChoice这款应用带给了大家革命性的交互体验,app store地址:https://itunes.apple.com/cn/app/al-gore-our-choice-plan-to/id432753658?mt=8
本文将对OurChoice中的折叠特效实现进行说明。
实现折叠特效的主要思路为在UIView中添加UIPinchGestureRecognizer、UITapGestureRecognizer和UIPanGestureRecognizer,以响应特效中的捏合、轻拍和移动。
初始化时,获取当前UIView的快照以UImage的形式渲染在两个layer上,一个layer占图片的一半。初始化代码如下:
- (void)initFoldLayer { if (!_foldLayer) { UIGraphicsBeginImageContext(self.frame.size); [self.layer renderInContext:UIGraphicsGetCurrentContext()]; UIImage *viewSnapShot = UIGraphicsGetImageFromCurrentImageContext(); UIGraphicsEndImageContext(); CATransform3D transform = CATransform3DIdentity; transform.m34 = -1.0/1200.0; _shadowLayer = [[CALayer layer] retain]; _shadowLayer.frame = self.bounds; _shadowLayer.shadowColor = [UIColor blackColor].CGColor; _shadowLayer.shadowOpacity = 0.5; _shadowLayer.shadowOffset = CGSizeMake(0, 0); _shadowLayer.shadowRadius = 2.0f; //阴影位置 _shadowLayer.shadowPath = [UIBezierPath bezierPathWithRect:[self getShowRect]].CGPath; [self.layer addSublayer:_shadowLayer]; [_shadowLayer setHidden:YES]; _foldLayer = [[CALayer layer] retain]; _foldLayer.frame = self.bounds; _foldLayer.backgroundColor = [UIColor clearColor].CGColor; _foldLayer.sublayerTransform = transform; [_foldLayer setHidden:YES]; [self.layer addSublayer:_foldLayer]; for (int i = 0; i < 2; i++) { CGRect frame; //不同方向截取图片的区域不同 if (_foldViewType == TSFoldViewTypeUp || _foldViewType == TSFoldViewTypeDown) { frame = CGRectMake(0, i * self.frame.size.height/2, self.frame.size.width, self.frame.size.height/2); }else { frame = CGRectMake(i * self.frame.size.width/2, 0, self.frame.size.width/2, self.frame.size.height); } CGImageRef imageCrop = CGImageCreateWithImageInRect(viewSnapShot.CGImage, frame); CALayer *imageCroppedLayer = [CALayer layer]; imageCroppedLayer.frame = frame; //不同方向锚点不同 if (_foldViewType == TSFoldViewTypeUp || _foldViewType == TSFoldViewTypeDown) { imageCroppedLayer.anchorPoint = CGPointMake(0.5, !i); }else { imageCroppedLayer.anchorPoint = CGPointMake(!i, 0.5); } imageCroppedLayer.position = CGPointMake(self.frame.size.width/2, self.frame.size.height/2); imageCroppedLayer.contents = (id)imageCrop; imageCroppedLayer.backgroundColor = [UIColor clearColor].CGColor; [_foldLayer addSublayer:imageCroppedLayer]; //不同方向摆放次序不同 if (_foldViewType == TSFoldViewTypeLeft || _foldViewType == TSFoldViewTypeUp) { [_foldLayer insertSublayer:imageCroppedLayer atIndex:0]; } //设置标识符 if (i == 0) { imageCroppedLayer.name = @"first"; }else { imageCroppedLayer.name = @"second"; } //设置初始的角度 if (_foldViewType == TSFoldViewTypeLeft && i == 1) { imageCroppedLayer.transform = CATransform3DMakeRotation(M_PI, 0, 1, 0); }else if (_foldViewType == TSFoldViewTypeRight && i == 0) { imageCroppedLayer.transform = CATransform3DMakeRotation(M_PI, 0, 1, 0); }else if (_foldViewType == TSFoldViewTypeUp && i == 1) { imageCroppedLayer.transform = CATransform3DMakeRotation(M_PI, 1, 0, 0); }else if (_foldViewType == TSFoldViewTypeDown && i == 0) { imageCroppedLayer.transform = CATransform3DMakeRotation(M_PI, 1, 0, 0); } CAGradientLayer *shadowLayer = [CAGradientLayer layer]; shadowLayer.frame = imageCroppedLayer.bounds; shadowLayer.opacity = 0; shadowLayer.colors = [NSArray arrayWithObjects:(id)[UIColor blackColor].CGColor, (id)[UIColor colorWithRed:1/3.0f green:1/3.0f blue:1/3.0f alpha:0.5f].CGColor, nil]; //设置渐变的位置 if (_foldViewType == TSFoldViewTypeLeft || _foldViewType == TSFoldViewTypeRight) { if (i == 0) { shadowLayer.startPoint = CGPointMake(0, 0.5); shadowLayer.endPoint = CGPointMake(1, 0.5); } else { shadowLayer.startPoint = CGPointMake(1, 0.5); shadowLayer.endPoint = CGPointMake(0, 0.5); } }else { if (i == 0) { shadowLayer.startPoint = CGPointMake(0.5, 0); shadowLayer.endPoint = CGPointMake(0.5, 1); } else { shadowLayer.startPoint = CGPointMake(0.5, 1); shadowLayer.endPoint = CGPointMake(0.5, 0); } } [imageCroppedLayer addSublayer:shadowLayer]; } [self setFoldLayerHidden:NO]; } }
手指捏合时,根据手指之间的距离计算当前两个layer倾斜的角度,形成折叠的效果。响应捏合手势的代码如下:
- (void)modifiedGesture:(UIGestureRecognizer *)gesture { if (gesture.numberOfTouches < 2) { return; } CGPoint pos1 = [gesture locationOfTouch:0 inView:self]; CGPoint pos2 = [gesture locationOfTouch:1 inView:self]; CGPoint middlePos = CGPointMake((pos1.x + pos2.x)/2, (pos1.y + pos2.y)/2); CGFloat dis = [self getDisBetweenPoint1:pos1 point2:pos2]; if ([gesture isKindOfClass:[UIPinchGestureRecognizer class]]) { if (dis > kMinDistance && dis < _maxDistance) { _currentAngle = M_PI_2 - ((dis / _maxDistance) * M_PI / 2); if (_foldViewType == TSFoldViewTypeLeft || _foldViewType == TSFoldViewTypeRight) { _shadowLayer.shadowPath = [UIBezierPath bezierPathWithRect:CGRectMake((self.bounds.size.width - (dis / _maxDistance) * self.bounds.size.width)/2, 150, (dis / _maxDistance) * self.bounds.size.width, _shadowLayer.frame.size.height - 150)].CGPath; _pinchTransform = CATransform3DMakeRotation(_currentAngle, 0, 1, 0); }else { _shadowLayer.shadowPath = [UIBezierPath bezierPathWithRect:CGRectMake(0, (self.bounds.size.height - (dis / _maxDistance) * self.bounds.size.height)/2, _shadowLayer.frame.size.width, (dis / _maxDistance) * self.bounds.size.height)].CGPath; _pinchTransform = CATransform3DMakeRotation(-_currentAngle, 1, 0, 0); } } }else if ([gesture isKindOfClass:[UIPanGestureRecognizer class]]) { UIPanGestureRecognizer *pan = (UIPanGestureRecognizer *)gesture; CGPoint translation = [pan translationInView:self.superview]; _panTransform = CATransform3DTranslate(_panTransform, translation.x, translation.y, 0); [pan setTranslation:CGPointZero inView:self.superview]; } //根据位置和角度设置layer的阴影 [CATransaction begin]; [CATransaction setDisableActions:YES]; [self setLayerShadow:middlePos distance:dis]; [CATransaction commit]; [CATransaction begin]; [CATransaction setAnimationDuration:0.1]; for (int i=0; i<[[_foldLayer sublayers] count]; i++) { CALayer *layer = [[_foldLayer sublayers] objectAtIndex:i]; if ([layer.name isEqualToString:@"first"]) { layer.transform = CATransform3DConcat(CATransform3DConcat(CATransform3DInvert(_pinchTransform), _scaleTransform), _panTransform); }else if ([layer.name isEqualToString:@"second"]) { layer.transform = CATransform3DConcat(CATransform3DConcat(_pinchTransform, _scaleTransform), _panTransform); } } _shadowLayer.transform = _panTransform; [CATransaction commit]; }最终实现效果如下:
Demo工程已上传至CSDN资源:http://download.csdn.net/detail/zhaoxy2850/5710433