iOS OurChoice折叠特效实现

来源:互联网 发布:我想学计算机编程 编辑:程序博客网 时间:2024/05/16 17:18

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

原创粉丝点击