2

我设置了一个视图,这样当应用程序向前导航时,它transitionFromView使用该UIViewAnimationOptionTransitionFlipFromRight选项执行。这会产生如下效果:

使用 UIViewAnimationOptionTransitionFlipFromRight

向后导航使用UIViewAnimationOptionTransitionFlipFromLeft,但其他方面相同。好的,到目前为止,一切都很好。

现在,我还设置了一个UIPanGestureRecognizer,以便我可以将视图的翻转与用户在屏幕上的水平手势联系起来。但显然我不能transitionFromView在那种情况下使用,所以我的手势识别器是手动设置 with 的transform属性layer

CATransform3D transform = CATransform3DIdentity;
transform.m34 = 1.0 / -800.0;
viewToTransform.layer.transform = CATransform3DRotate(transform, M_PI * rotationPercent, 0.0, 1.0, 0.0);

但这会产生微妙的不同效果:

CATransform3D旋转

在翻转动画期间视图的UIViewAnimationOptionTransitionFlipFromRight选项transitionFromView被缩放,以便翻转视图的最高边缘保持容器视图的高度。但是当手动执行 时transformlayer视图的中心保持不变的大小,在动画期间略微裁剪翻转视图的较长边缘的角。

transform在我的手势识别器中设置属性时如何实现这种效果layer(我可能也想调整我opacity的 ,以获得轻微的调光效果transitionFromView)。我想我可以使用CATransform3DMakeScale并根据旋转角度和我的特定m34设置手动计算缩放函数,但在我进行那个练习之前,我想确保我没有忽略一些更直观或更自然的方法实现标准翻转动画所需的同时缩放和旋转。即使我必须手动计算比例因子,我也会很感激关于如何将它定义为m34设置和角度的函数的指导(我不是矢量变换的精妙之处的专家)。

4

2 回答 2

4

变换都基于您的图层锚点。那是您旋转的“枢轴点”。

anchorPoint 在 x 和 y 中使用从 0 到 1 的比例,默认为 0.5、0.5

我相信您会希望您的图层设置如下所示:

viewToTransform.layer.anchorPoint = CGPointMake(0.5, 1);

这个问题的答案中有一些很好的信息和研究地点:

更改我的 CALayer 的锚点会移动视图

于 2013-04-06T14:57:03.263 回答
2

HalR 是正确的,为了达到预期的效果,应该改变anchorPoint. 因此,对于围绕视图右边缘旋转的水平翻转,可以按如下方式设置锚点:

viewToTransform.layer.anchorPoint = CGPointMake(1, 0.5);

但是,这也会改变视图,因此需要将新值anchorPointCATransform3D将视图转换回原来位置的值相结合。例如,这是一个 Swift 3 自定义过渡“动画控制器”,它执行水平翻转动画。

class HorizontalFlipAnimationController: NSObject, UIViewControllerAnimatedTransitioning {

    enum TransitionType {
        case presenting
        case dismissing
    }

    let transitionType: TransitionType

    init(transitionType: TransitionType) {
        self.transitionType = transitionType

        super.init()
    }

    func animateTransition(using transitionContext: UIViewControllerContextTransitioning) {
        let inView   = transitionContext.containerView
        let toView   = transitionContext.view(forKey: .to)!
        let fromView = transitionContext.view(forKey: .from)!

        var frame = inView.bounds

        func flipTransform(angle: CGFloat, offset: CGFloat = 0) -> CATransform3D {
            var transform = CATransform3DMakeTranslation(offset, 0, 0)
            transform.m34 = -1.0 / 1600
            transform = CATransform3DRotate(transform, angle, 0, 1, 0)
            return transform
        }

        toView.frame = inView.bounds
        toView.alpha = 0

        let transformFromStart:  CATransform3D
        let transformFromEnd:    CATransform3D
        let transformFromMiddle: CATransform3D
        let transformToStart:    CATransform3D
        let transformToMiddle:   CATransform3D
        let transformToEnd:      CATransform3D

        switch transitionType {
        case .presenting:
            transformFromStart  = flipTransform(angle: 0,        offset: inView.bounds.size.width / 2)
            transformFromEnd    = flipTransform(angle: -.pi,     offset: inView.bounds.size.width / 2)
            transformFromMiddle = flipTransform(angle: -.pi / 2)
            transformToStart    = flipTransform(angle: .pi,      offset: -inView.bounds.size.width / 2)
            transformToMiddle   = flipTransform(angle: .pi / 2)
            transformToEnd      = flipTransform(angle: 0,        offset: -inView.bounds.size.width / 2)

            toView.layer.anchorPoint = CGPoint(x: 0, y: 0.5)
            fromView.layer.anchorPoint = CGPoint(x: 1, y: 0.5)

        case .dismissing:
            transformFromStart  = flipTransform(angle: 0,        offset: -inView.bounds.size.width / 2)
            transformFromEnd    = flipTransform(angle: .pi,      offset: -inView.bounds.size.width / 2)
            transformFromMiddle = flipTransform(angle: .pi / 2)
            transformToStart    = flipTransform(angle: -.pi,     offset: inView.bounds.size.width / 2)
            transformToMiddle   = flipTransform(angle: -.pi / 2)
            transformToEnd      = flipTransform(angle: 0,        offset: inView.bounds.size.width / 2)

            toView.layer.anchorPoint = CGPoint(x: 1, y: 0.5)
            fromView.layer.anchorPoint = CGPoint(x: 0, y: 0.5)
        }

        toView.layer.transform = transformToStart
        fromView.layer.transform = transformFromStart
        inView.addSubview(toView)

        UIView.animateKeyframes(withDuration: self.transitionDuration(using: transitionContext), delay: 0, options: [], animations: {
            UIView.addKeyframe(withRelativeStartTime: 0, relativeDuration: 0.0) {
                toView.alpha = 0
                fromView.alpha = 1
            }
            UIView.addKeyframe(withRelativeStartTime: 0, relativeDuration: 0.5) {
                toView.layer.transform = transformToMiddle
                fromView.layer.transform = transformFromMiddle
            }
            UIView.addKeyframe(withRelativeStartTime: 0.5, relativeDuration: 0.0) {
                toView.alpha = 1
                fromView.alpha = 0
            }
            UIView.addKeyframe(withRelativeStartTime: 0.5, relativeDuration: 0.5) {
                toView.layer.transform = transformToEnd
                fromView.layer.transform = transformFromEnd
            }
        }, completion: { finished in
            toView.layer.transform = CATransform3DIdentity
            fromView.layer.transform = CATransform3DIdentity
            toView.layer.anchorPoint = CGPoint(x: 0.5, y: 0.5)
            fromView.layer.anchorPoint = CGPoint(x: 0.5, y: 0.5)

            transitionContext.completeTransition(!transitionContext.transitionWasCancelled)
        })
    }

    func transitionDuration(using transitionContext: UIViewControllerContextTransitioning?) -> TimeInterval {
        return 1.0
    }
}

这会产生:

示例翻转

于 2017-02-13T20:49:52.273 回答