iOS OurChoice折叠特效实现

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

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值