4

我有一张卡片的正面和背面。我像这样动画两者之间的过渡:

private func flipToBack() {
    UIView.transition(from: frontContainer, to: backContainer, duration: 0.5, options: [.transitionFlipFromRight, .showHideTransitionViews], completion: nil)
}

private func flipToFront() {
    UIView.transition(from: backContainer, to: frontContainer, duration: 0.5, options: [.transitionFlipFromLeft, .showHideTransitionViews], completion: nil)
}

这完美地工作。但是,我想让这个动画具有交互性,这样如果用户在卡片上水平平移,翻转动画将按比例推进。通常,我会使用UIViewPropertyAnimator.

是否可以使用UIViewPropertyAnimator,或者是否有其他替代方法可以使翻转互动?

4

1 回答 1

4

最后是我自己写的。代码很长,所以这里是GitHub 上完整程序的链接。以下是关键部分:

一切都封装在一个InteractiveFlipAnimator对象中,该对象具有前视图 ( v1) 和后视图 ( v2)。每个视图也有一个黑色的封面,作为一个阴影,当视图变成透视图时添加变暗效果。

这是平移功能:

/// Add a `UIPanGestureRecognizer` to the main view that contains the card and pass it onto this function.
@objc func pan(_ gesture: UIPanGestureRecognizer) {
    guard let view = gesture.view else { return }
    if isAnimating { return }

    let translation = gesture.translation(in: view)
    let x = translation.x
    let angle = startAngle + CGFloat.pi * x / view.frame.width

    // If the angle is outside [-pi, 0], then do not rotate the view and count it as touchesEnded. This works because the full width is the screen width.
    if angle < -CGFloat.pi || angle > 0 {
        if gesture.state != .began && gesture.state != .changed {
            finishedPanning(angle: angle, velocity: gesture.velocity(in: view))
        }
        return
    }

    var transform = CATransform3DIdentity
    // Perspective transform
    transform.m34 = 1 / -500
    // y rotation transform
    transform = CATransform3DRotate(transform, angle, 0, 1, 0)
    self.v1.layer.transform = transform
    self.v2.layer.transform = transform

    // Set the shadow
    if startAngle == 0 {
        self.v1Cover.alpha = 1 - abs(x / view.frame.width)
        self.v2Cover.alpha = abs(x / view.frame.width)
    } else {
        self.v1Cover.alpha = abs(x / view.frame.width)
        self.v2Cover.alpha = 1 - abs(x / view.frame.width)
    }

    // Set which view is on top. This flip happens when it looks like the two views make a vertical line.
    if abs(angle) < CGFloat.pi / 2 {
        // Flipping point
        v1.layer.zPosition = 0
        v2.layer.zPosition = 1
    } else {
        v1.layer.zPosition = 1
        v2.layer.zPosition = 0
    }

    // Save state
    if gesture.state != .began && gesture.state != .changed {
        finishedPanning(angle: angle, velocity: gesture.velocity(in: view))
    }
}

完成平移的代码非常相似,但也更长。要查看所有内容,请访问上面的 GitHub 链接。

于 2018-10-28T21:08:27.897 回答