churabou / iOS-develop-blog

0 stars 0 forks source link

昔使ってたポップアップ #37

Open churabou opened 6 years ago

churabou commented 6 years ago

class BasePopUpView: BaseView {
    weak var controller: UIViewController?
    func setUpView(parent: UIView) { }
}

final class PopUpController: BaseController {

    convenience init(contentView: BasePopUpView,
                     presentTransition: UIViewControllerAnimatedTransitioning = BasePopUpTransition(),
                     dismissTransition: UIViewControllerAnimatedTransitioning = DefaultDismissTransition()) {
        self.init()
        self.contentView = contentView
        self.presentTransition = presentTransition
        self.dismissTransition = dismissTransition
    }

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

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

    override func viewDidLoad() {
        super.viewDidLoad()
        initializeView()
    }

    override func commonInit() {
        providesPresentationContextTransitionStyle = true
        definesPresentationContext = true
        modalPresentationStyle = .custom
        transitioningDelegate = self
    }

    private (set) var contentView = BasePopUpView()
    private var presentTransition: UIViewControllerAnimatedTransitioning?
    private var dismissTransition: UIViewControllerAnimatedTransitioning?

    override func initializeView() {
        contentView.setUpView(parent: view)
        contentView.controller = self
    }
}

extension PopUpController: UIViewControllerTransitioningDelegate {

    func animationController(forDismissed dismissed: UIViewController) -> UIViewControllerAnimatedTransitioning? {
        return dismissTransition
    }

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

class BasePopUpTransition: NSObject {

    var duration: TimeInterval {
        return 0.4
    }

    func animation(toView: UIView, contentView: UIView, completion: @escaping ((Bool) -> Swift.Void)) {

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

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

        animator.addCompletion { _ in
            completion(true)
        }

        animator.startAnimation()
    }
}

extension BasePopUpTransition: UIViewControllerAnimatedTransitioning {

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

    func animateTransition(using transitionContext: UIViewControllerContextTransitioning) {

        let containerView = transitionContext.containerView

        guard let popUpVC = transitionContext.viewController(forKey: .to) as? PopUpController,
        let toView = popUpVC.view else {
            return
        }

        containerView.addSubview(toView)

        animation(toView: toView, contentView: popUpVC.contentView) { result in
            transitionContext.completeTransition(result)
        }

    }
}

class DefaultDismissTransition: NSObject, UIViewControllerAnimatedTransitioning {

    private var duration: TimeInterval = 0.2

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

    func animateTransition(using transitionContext: UIViewControllerContextTransitioning) {

        guard let fromView = transitionContext.view(forKey: .from) else {
            return
        }

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

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

        animator.startAnimation()
    }
}
churabou commented 5 years ago

使い方


final class ResultPopUpView: BasePopUpView {

    // called after viewdidload
    override func setUpView(parent: UIView) {
        parent.backgroundColor = UIColor(white: 0, alpha: 0.3)
        parent.addSubview(self)

        backgroundColor = .blue
        bounds.size = CGSize(width: 300, height: 400)
        center = parent.center

        addSubview(doneButton)
        doneButton.frame = .init(x: 20, y: 300, width: 260, height: 80)
    }

    private lazy var doneButton: UIButton = {
        let b = UIButton()
        b.setTitle("完了", for: .normal)
        b.setTitleColor(.white, for: .normal)
        b.backgroundColor = .white
        b.addTarget(self, action: #selector(actionClose), for: .touchUpInside)
        return b
    }()

    @objc private func actionClose() {
        controller?.dismiss(animated: true, completion: nil)
    }
}
        let c = PopUpController(contentView: ResultPopUpView())
        present(c, animated: true, completion: nil)