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