杨锴
2024-11-06 63f7ed967433acee3ae8764c7a077e15c29c41f2
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
//
//  CLAnimationTransitioning.swift
//  CLPlayer
//
//  Created by Chen JmoVxia on 2021/10/27.
//
 
import SnapKit
import UIKit
 
extension CLAnimationTransitioning {
    enum AnimationType {
        case present
        case dismiss
    }
 
    enum AnimationOrientation {
        case left
        case right
        case fullRight
    }
}
 
class CLAnimationTransitioning: NSObject {
    private let keyWindow: UIWindow? = {
        if #available(iOS 13.0, *) {
            return UIApplication.shared.windows.filter { $0.isKeyWindow }.last
        } else {
            return UIApplication.shared.keyWindow
        }
    }()
 
    private weak var playerView: CLPlayerView?
 
    private weak var parentStackView: UIStackView?
 
    private var initialCenter: CGPoint = .zero
 
    private var finalCenter: CGPoint = .zero
 
    private var initialBounds: CGRect = .zero
 
    private var animationOrientation: AnimationOrientation = .left
 
    var animationType: AnimationType = .present
 
    init(playerView: CLPlayerView, animationOrientation: AnimationOrientation) {
        self.playerView = playerView
        self.animationOrientation = animationOrientation
        parentStackView = playerView.superview as? UIStackView
        initialBounds = playerView.bounds
        initialCenter = playerView.center
        finalCenter = playerView.convert(initialCenter, to: nil)
    }
}
 
extension CLAnimationTransitioning: UIViewControllerAnimatedTransitioning {
    func transitionDuration(using _: UIViewControllerContextTransitioning?) -> TimeInterval {
        return 0.35
    }
 
    func animateTransition(using transitionContext: UIViewControllerContextTransitioning) {
        guard let playerView = playerView else { return }
 
        if animationType == .present {
            guard let toView = transitionContext.view(forKey: .to) else { return }
            guard let toController = transitionContext.viewController(forKey: .to) as? CLFullScreenController else { return }
 
            let startCenter = transitionContext.containerView.convert(initialCenter, from: playerView)
            transitionContext.containerView.addSubview(toView)
            toController.mainStackView.addArrangedSubview(playerView)
            toView.bounds = initialBounds
            toView.center = startCenter
            toView.transform = .init(rotationAngle: toController.isKind(of: CLFullScreenLeftController.self) ? Double.pi * 0.5 : Double.pi * -0.5)
 
            if #available(iOS 11.0, *) {
                playerView.contentView.animationLayout(safeAreaInsets: keyWindow?.safeAreaInsets ?? .zero, to: .fullScreen)
            } else {
                playerView.contentView.animationLayout(safeAreaInsets: .zero, to: .fullScreen)
            }
            UIView.animate(withDuration: transitionDuration(using: transitionContext), delay: 0, options: .layoutSubviews, animations: {
                toView.transform = .identity
                toView.bounds = transitionContext.containerView.bounds
                toView.center = transitionContext.containerView.center
                playerView.contentView.setNeedsLayout()
                playerView.contentView.layoutIfNeeded()
            }) { _ in
                toView.transform = .identity
                toView.bounds = transitionContext.containerView.bounds
                toView.center = transitionContext.containerView.center
                transitionContext.completeTransition(true)
                UIViewController.attemptRotationToDeviceOrientation()
            }
        } else {
            guard let parentStackView = parentStackView else { return }
            guard let fromView = transitionContext.view(forKey: .from) else { return }
            guard let toView = transitionContext.view(forKey: .to) else { return }
 
            transitionContext.containerView.addSubview(toView)
            transitionContext.containerView.addSubview(fromView)
            toView.frame = transitionContext.containerView.bounds
 
            playerView.contentView.animationLayout(safeAreaInsets: .zero, to: .small)
            UIView.animate(withDuration: transitionDuration(using: transitionContext), delay: 0.0, options: .layoutSubviews, animations: {
                fromView.transform = .identity
                fromView.center = self.finalCenter
                fromView.bounds = self.initialBounds
                playerView.contentView.setNeedsLayout()
                playerView.contentView.layoutIfNeeded()
            }) { _ in
                fromView.transform = .identity
                fromView.center = self.finalCenter
                fromView.bounds = self.initialBounds
                parentStackView.addArrangedSubview(playerView)
                fromView.removeFromSuperview()
                transitionContext.completeTransition(true)
                UIViewController.attemptRotationToDeviceOrientation()
            }
        }
    }
}