churabou / iOS-develop-blog

0 stars 0 forks source link

[未解決] #35

Closed churabou closed 6 years ago

churabou commented 6 years ago
import UIKit

class ViewController: UIViewController {

    override func viewDidLoad() {

        let label = UILabel()
        label.textColor = .white
        label.textAlignment = .center
        label.text = "pop up"
        label.sizeToFit()
        label.center = view.center

        view.backgroundColor = .green
        view.addSubview(label)
    }

    override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {

        let c = CustomViewController()
        c.modalPresentationStyle = .overCurrentContext
        self.present(c,  animated: true, completion: nil)
    }
}

class Animator : NSObject {

    private let isPresenting: Bool

    fileprivate var duration: TimeInterval {
        return isPresenting ? 0.45 : 0.25
    }

    init(isPresenting: Bool) {
        self.isPresenting = isPresenting
    }

    func presentAnimateTransition(_ transitionContext: UIViewControllerContextTransitioning) {

        let to = transitionContext.viewController(forKey: .to)!
        let containerView = transitionContext.containerView

        to.view.alpha = 0.0
        containerView.addSubview(to.view)

        UIView.animate(withDuration: 0.45,
                       animations: {
                        to.view.alpha = 1.0
        },
                       completion: { finished in
                        transitionContext.completeTransition(true)
        })
    }

    func dismissAnimateTransition(_ transitionContext: UIViewControllerContextTransitioning) {
    }
}

extension Animator: UIViewControllerAnimatedTransitioning {

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

    func animateTransition(using transitionContext: UIViewControllerContextTransitioning) {

        print("animate transition")
        if (isPresenting) {
            self.presentAnimateTransition(transitionContext)
        } else {
            self.dismissAnimateTransition(transitionContext)
        }
    }
}

class CustomViewController: UIViewController {

    override func viewDidLoad() {
        view.backgroundColor = .red
        transitioningDelegate = self
        print("view did load")

        view.backgroundColor = .clear

        let b = UIButton()
        view.addSubview(b)
        b.frame.size = .init(width: 100, height: 100)
        b.center = view.center
        b.backgroundColor = .cyan
        b.addTarget(self, action: #selector(actionTap), for: .touchUpInside)
    }

    override func viewDidAppear(_ animated: Bool) {
        print("view did appear")
    }

    @objc private func actionTap() {
        self.dismiss(animated: false, completion: nil)
    }
}

extension CustomViewController: UIViewControllerTransitioningDelegate {

    func animationController(forDismissed dismissed: UIViewController) -> UIViewControllerAnimatedTransitioning? {
        return Animator(isPresenting: true)
    }

    func animationController(forPresented presented: UIViewController, presenting: UIViewController, source: UIViewController) -> UIViewControllerAnimatedTransitioning? {
        return Animator(isPresenting: true)
    }
}

カスタムアニメーションを適応させたい。 また遷移前のViewをすかしたい。 ただ c.modalPresentationStyle = .overCurrentContext

を設定してしまうと、カスタムアニメーションが動作しない

churabou commented 6 years ago
import UIKit

class ResultViewController: UIViewController {

    private (set) var contentView = UIView()
    private var overlayView = UIView()
    private var button = UIButton()

    override init(nibName nibNameOrNil: String?, bundle nibBundleOrNil: Bundle?) {
        super.init(nibName: nil, bundle: nil)

        providesPresentationContextTransitionStyle = true
        definesPresentationContext = true
        modalPresentationStyle = .custom
        transitioningDelegate = self
    }

    required init?(coder aDecoder: NSCoder) {
        fatalError("init(coder:) has not been implemented")
    }

    override func viewDidLoad() {

        view.backgroundColor = .clear
        overlayView.frame = view.bounds
        overlayView.backgroundColor = UIColor(white: 0, alpha: 0.3)
        view.addSubview(overlayView)

        contentView.translatesAutoresizingMaskIntoConstraints = false
        contentView.backgroundColor = .white
        contentView.layer.cornerRadius = 30
        view.addSubview(contentView)

        NSLayoutConstraint.activate([
            contentView.centerXAnchor.constraint(equalTo: view.centerXAnchor),
            contentView.centerYAnchor.constraint(equalTo: view.centerYAnchor),
            contentView.widthAnchor.constraint(equalToConstant: 300),
            contentView.heightAnchor.constraint(equalToConstant: 250)
        ])

        button.translatesAutoresizingMaskIntoConstraints = false
        button.setTitle("OK", for: .normal)
        button.setTitleColor(.white, for: .normal)
        //        button.titleLabel?.textColor = .white
        //         button.titleLabel?.text = "OK"
        button.backgroundColor = .cyan
        button.addTarget(self, action: #selector(actionClose), for: .touchUpInside)
        button.layer.cornerRadius = 25
        contentView.addSubview(button)

        NSLayoutConstraint.activate([
            button.leftAnchor.constraint(equalTo: contentView.leftAnchor, constant: 30),
            button.rightAnchor.constraint(equalTo: contentView.rightAnchor, constant: -30),
            button.bottomAnchor.constraint(equalTo: contentView.bottomAnchor, constant: -20),
            button.heightAnchor.constraint(equalToConstant: 50)
        ])
    }

    @objc private func actionClose() {
        dismiss(animated: true, completion: nil)
    }
}

extension ResultViewController: UIViewControllerTransitioningDelegate {

    func animationController(forDismissed dismissed: UIViewController) -> UIViewControllerAnimatedTransitioning? {
        return PopUpTransition(.dismiss)
    }

    func animationController(forPresented presented: UIViewController, presenting: UIViewController, source: UIViewController) -> UIViewControllerAnimatedTransitioning? {
        return PopUpTransition(.present)
    }
}

final class PopUpTransition: NSObject {

    private var duration: TimeInterval {
      return  mode == .present ? 0.4 : 0.2
    }

    private var mode: TransitionMode

    init(_ mode: TransitionMode) {
        self.mode = mode
    }

    func presentAnimation(_ transitionContext: UIViewControllerContextTransitioning) {

        let containerView = transitionContext.containerView

        guard let resultVC = transitionContext.viewController(forKey: .to) as? ResultViewController else {
            return
        }

        let toView = resultVC.view!
        containerView.addSubview(toView)

        toView.alpha = 0
        resultVC.contentView.transform = CGAffineTransform.identity.scaledBy(x: 0.95, y: 0.95)

        let animator = UIViewPropertyAnimator(duration: duration, curve: .easeInOut) {
            toView.alpha = 1
            resultVC.contentView.transform = .identity
        }

        animator.addCompletion { _ in
            transitionContext.completeTransition(true)
        }

        animator.startAnimation()
    }

    func dismissAnimation(_ transitionContext: UIViewControllerContextTransitioning) {

         print("呼ばれた。dismissAnimation")
        guard let fromView = transitionContext.view(forKey: .from) else {
            fatalError("from view")
        }

        let animator = UIViewPropertyAnimator(duration: duration, curve: .easeInOut) {
            fromView.alpha = 0
        }

        animator.addCompletion { _ in
            transitionContext.completeTransition(true)
        }

        animator.startAnimation()
    }
}

extension PopUpTransition: UIViewControllerAnimatedTransitioning {

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

    func animateTransition(using transitionContext: UIViewControllerContextTransitioning) {

        switch mode {
        case .present:
            presentAnimation(transitionContext)
        case .dismiss:
            dismissAnimation(transitionContext)
        }
    }
}