正在UICollectionViewCell上创建视差聚焦效果



如何使用自定义视图在集合视图单元格上创建视差聚焦效果?如果我使用的是图像视图,则要设置的属性将是adjustsImageWhenAncestorFocused,但我的集合视图单元格包含一个子类UIView,其中包含使用核心图形绘制的自定义内容。

@raulriera的答案很好,但只是在2D中移动单元格。此外,OP要求提供一个objective-C示例。

出于完全相同的原因,我也希望实现这种效果——我使用了UICollectionView,其中的单元格包含图像和标签。

我创建了一个UIMotionEffectGroup子类,因为接近Apple TV效果似乎需要四种不同的运动效果。前两个是@raulriera中的平面运动,另外两个是3D旋转。

现在只剩下闪亮的环境层了。有买家吗?:-)

这是我的运动效果组代码:

(shiftDistance和tiltAngle常数设置了效果的大小。给定的值看起来与苹果电视的效果非常相似。)

#import <UIKit/UIKit.h>
#import "UIAppleTvMotionEffectGroup.h"
@implementation UIAppleTvMotionEffectGroup
- (id)init
{
    if ((self = [super init]) != nil)
    {
        // Size of shift movements
        CGFloat const shiftDistance = 10.0f;
        // Make horizontal movements shift the centre left and right
        UIInterpolatingMotionEffect *xShift = [[UIInterpolatingMotionEffect alloc]
                                              initWithKeyPath:@"center.x"
                                              type:UIInterpolatingMotionEffectTypeTiltAlongHorizontalAxis];
        xShift.minimumRelativeValue = [NSNumber numberWithFloat: shiftDistance * -1.0f];
        xShift.maximumRelativeValue = [NSNumber numberWithFloat: shiftDistance];
        // Make vertical movements shift the centre up and down
        UIInterpolatingMotionEffect *yShift = [[UIInterpolatingMotionEffect alloc]
                                              initWithKeyPath:@"center.y"
                                              type:UIInterpolatingMotionEffectTypeTiltAlongVerticalAxis];
        yShift.minimumRelativeValue = [NSNumber numberWithFloat: shiftDistance * -1.0f];
        yShift.maximumRelativeValue = [NSNumber numberWithFloat: shiftDistance];
        // Size of tilt movements
        CGFloat const tiltAngle = M_PI_4 * 0.125;
        // Now make horizontal movements effect a rotation about the Y axis for side-to-side rotation.
        UIInterpolatingMotionEffect *xTilt = [[UIInterpolatingMotionEffect alloc] initWithKeyPath:@"layer.transform" type:UIInterpolatingMotionEffectTypeTiltAlongHorizontalAxis];
        // CATransform3D value for minimumRelativeValue
        CATransform3D transMinimumTiltAboutY = CATransform3DIdentity;
        transMinimumTiltAboutY.m34 = 1.0 / 500;
        transMinimumTiltAboutY = CATransform3DRotate(transMinimumTiltAboutY, tiltAngle * -1.0, 0, 1, 0);
        // CATransform3D value for maximumRelativeValue
        CATransform3D transMaximumTiltAboutY = CATransform3DIdentity;
        transMaximumTiltAboutY.m34 = 1.0 / 500;
        transMaximumTiltAboutY = CATransform3DRotate(transMaximumTiltAboutY, tiltAngle, 0, 1, 0);
        // Set the transform property boundaries for the interpolation
        xTilt.minimumRelativeValue = [NSValue valueWithCATransform3D: transMinimumTiltAboutY];
        xTilt.maximumRelativeValue = [NSValue valueWithCATransform3D: transMaximumTiltAboutY];
        // Now make vertical movements effect a rotation about the X axis for up and down rotation.
        UIInterpolatingMotionEffect *yTilt = [[UIInterpolatingMotionEffect alloc] initWithKeyPath:@"layer.transform" type:UIInterpolatingMotionEffectTypeTiltAlongVerticalAxis];
        // CATransform3D value for minimumRelativeValue
        CATransform3D transMinimumTiltAboutX = CATransform3DIdentity;
        transMinimumTiltAboutX.m34 = 1.0 / 500;
        transMinimumTiltAboutX = CATransform3DRotate(transMinimumTiltAboutX, tiltAngle * -1.0, 1, 0, 0);
        // CATransform3D value for maximumRelativeValue
        CATransform3D transMaximumTiltAboutX = CATransform3DIdentity;
        transMaximumTiltAboutX.m34 = 1.0 / 500;
        transMaximumTiltAboutX = CATransform3DRotate(transMaximumTiltAboutX, tiltAngle, 1, 0, 0);
        // Set the transform property boundaries for the interpolation
        yTilt.minimumRelativeValue = [NSValue valueWithCATransform3D: transMinimumTiltAboutX];
        yTilt.maximumRelativeValue = [NSValue valueWithCATransform3D: transMaximumTiltAboutX];
        // Add all of the motion effects to this group
        self.motionEffects = @[xShift, yShift, xTilt, yTilt];
        [xShift release];
        [yShift release];
        [xTilt release];
        [yTilt release];
    }
    return self;
}
@end

我在我的自定义UICollectionViewCell子类中这样使用它:

@implementation MyCollectionViewCell
- (void)didUpdateFocusInContext:(UIFocusUpdateContext *)context withAnimationCoordinator:(UIFocusAnimationCoordinator *)coordinator
{
    // Create a static instance of the motion effect group (could do this anywhere, really, maybe init would be better - we only need one of them.)
    static UIAppleTVMotionEffectGroup *s_atvMotionEffect = nil;
    if (s_atvMotionEffect == nil)
    {
        s_atvMotionEffect = [[UIAppleTVMotionEffectGroup alloc] init];
    }
    [coordinator addCoordinatedAnimations: ^{
        if (self.focused)
        {
            [self addMotionEffect: s_atvMotionEffect];
        }
        else
        {
            [self removeMotionEffect: s_atvMotionEffect];
        }
                               completion: ^{
            }];
}
@end

您所需要做的就是将UIMotionEffect添加到子视图中。像这样的

override func didUpdateFocusInContext(context: UIFocusUpdateContext, withAnimationCoordinator coordinator: UIFocusAnimationCoordinator) {
    coordinator.addCoordinatedAnimations({ [unowned self] in
        if self.focused {
            let verticalMotionEffect = UIInterpolatingMotionEffect(keyPath: "center.y", type: .TiltAlongVerticalAxis)
            verticalMotionEffect.minimumRelativeValue = -10
            verticalMotionEffect.maximumRelativeValue = 10
            let horizontalMotionEffect = UIInterpolatingMotionEffect(keyPath: "center.x", type: .TiltAlongHorizontalAxis)
            horizontalMotionEffect.minimumRelativeValue = -10
            horizontalMotionEffect.maximumRelativeValue = 10
            let motionEffectGroup = UIMotionEffectGroup()
            motionEffectGroup.motionEffects = [horizontalMotionEffect, verticalMotionEffect]
            yourView.addMotionEffect(motionEffectGroup)
        }
        else {
            // Remove the effect here
        }
        }, completion: nil)
}

我已经将Simon Tillson的答案转换为swift 3.0,并发布在这里,为将来的人们节省打字时间。非常感谢您提供的解决方案。

class UIAppleTVMotionEffectGroup : UIMotionEffectGroup{
// size of shift movements
let shiftDistance : CGFloat = 10.0
let tiltAngle : CGFloat = CGFloat(M_PI_4) * 0.125
required init?(coder aDecoder: NSCoder) {
    super.init(coder: aDecoder)
}
override init() {
    super.init()
    // Make horizontal movements shift the centre left and right
    let xShift = UIInterpolatingMotionEffect(keyPath: "center.x", type: UIInterpolatingMotionEffectType.tiltAlongHorizontalAxis)
    xShift.minimumRelativeValue = shiftDistance * -1.0
    xShift.maximumRelativeValue = shiftDistance
    let yShift = UIInterpolatingMotionEffect(keyPath: "center.y", type: UIInterpolatingMotionEffectType.tiltAlongVerticalAxis)
    yShift.minimumRelativeValue = 0.0-shiftDistance
    yShift.maximumRelativeValue = shiftDistance
    let xTilt = UIInterpolatingMotionEffect(keyPath: "layer.transform", type: UIInterpolatingMotionEffectType.tiltAlongHorizontalAxis)
    var transMinimumTiltAboutY = CATransform3DIdentity
    transMinimumTiltAboutY.m34 = 1.0 / 500.0
    transMinimumTiltAboutY = CATransform3DRotate(transMinimumTiltAboutY, tiltAngle * -1.0, 0, 1, 0)
    var transMaximumTiltAboutY = CATransform3DIdentity
    transMaximumTiltAboutY.m34 = 1.0 / 500.0
    transMaximumTiltAboutY = CATransform3DRotate(transMaximumTiltAboutY, tiltAngle , 0, 1, 0)
    xTilt.minimumRelativeValue = transMinimumTiltAboutY
    xTilt.maximumRelativeValue = transMaximumTiltAboutY
    let yTilt = UIInterpolatingMotionEffect(keyPath: "layer.transform", type: UIInterpolatingMotionEffectType.tiltAlongVerticalAxis)
    var transMinimumTiltAboutX = CATransform3DIdentity
    transMinimumTiltAboutX.m34 = 1.0 / 500.0
    transMinimumTiltAboutX = CATransform3DRotate(transMinimumTiltAboutX, tiltAngle * -1.0, 1, 0, 0)
    var transMaximumTiltAboutX = CATransform3DIdentity
    transMaximumTiltAboutX.m34 = 1.0 / 500.0
    transMaximumTiltAboutX = CATransform3DRotate(transMaximumTiltAboutX, tiltAngle , 1, 0, 0)
    yTilt.minimumRelativeValue = transMinimumTiltAboutX
    yTilt.maximumRelativeValue = transMaximumTiltAboutX
    self.motionEffects = [xShift,yShift,xTilt,yTilt]
}

}

我在UICollectionView子类中添加了一个小pop。注意静态变量的结构包装器

  override func didUpdateFocus(in context: UIFocusUpdateContext, with coordinator: UIFocusAnimationCoordinator) {
    struct wrapper {
        static let s_atvMotionEffect = UIAppleTVMotionEffectGroup()
    }

    coordinator.addCoordinatedAnimations( {
        var scale : CGFloat = 0.0
        if self.isFocused {
            self.addMotionEffect(wrapper.s_atvMotionEffect)
            scale = 1.2
        } else {
            self.removeMotionEffect(wrapper.s_atvMotionEffect)
            scale = 1.0
        }
        let transform = CGAffineTransform(scaleX: scale, y: scale)
        self.layer.setAffineTransform(transform)
    },completion: nil)

}

相关内容

  • 没有找到相关文章

最新更新