Показать и скрыть модальные при запросе данных из API - PullRequest
0 голосов
/ 17 ноября 2018

У меня есть несколько запросов к моему API, которые, в то время как он делает запрос, я хочу показать полноэкранный модал со спиннером в середине, который переходит поверх текущей сцены.

Я настроилсцена в моей раскадровке, и я дал этой сцене контроллер:

class LoadingViewController: UIViewController {
    override func viewDidLoad() {
        super.viewDidLoad()

        // Do any additional setup after loading the view.
    }
}

В моем другом контроллере у меня есть следующее:

class SignInViewController: UIViewController {

    // MARK: Properties

    @IBOutlet weak var submitButton: UIButton!

    // MARK: Actions

    @IBAction func onSubmit(_ sender: Any) {
        // How do I show LoadingViewController as a modal here?
        // Later, how do I hide it?
    }

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

Как я прокомментировал выше, когда пользовательнажимает на кнопку «Отправить», я хочу показать полноэкранный режим через этот контроллерЗатем, когда API возвращает данные, я хочу скрыть модальное.

Как я могу показать и скрыть LoadingViewController как модальное поверх SignInViewController?

Ответы [ 2 ]

0 голосов
/ 17 ноября 2018

Чтобы использовать прозрачный фон с представленным контроллером представления, установите modalPresentationStyle = .custom в инициализаторе вашего LoadingViewController класса.

Чтобы использовать пользовательский переход с представленным контроллером представления, установите свойство transitioningDelegate вашего класса LoadingViewController и реализуйте UIViewControllerAnimatedTransitioning и UIViewControllerAnimatedTransitioning.

Например:

class LoadingViewController: UIViewController {

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

            transitioningDelegate = self        // Required for a custom transition.
            modalPresentationStyle = .custom    // Required for a transparent background.
    }

    // Other setup in your class...
}

extension LoadingViewController: UIViewControllerTransitioningDelegate {

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

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

extension LoadingViewController: UIViewControllerAnimatedTransitioning {

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

    func animateTransition(using transitionContext: UIViewControllerContextTransitioning) {

        if isBeingPresented {

            let toView = transitionContext.view(forKey: .to)!
            toView.alpha = 0

            transitionContext.containerView.addSubview(toView)
            UIView.animate(withDuration: 0.25,
                           animations: {
                toView.alpha = 1
            }, completion: { (_) in
                transitionContext.completeTransition(true)
            })

        } else {

            let fromView = transitionContext.view(forKey: .from)!

            UIView.animate(withDuration: 0.25,
                           animations: {
                fromView.alpha = 0
            }, completion: { (_) in
                fromView.removeFromSuperview()
                transitionContext.completeTransition(true)
            })
        }
    }
}

Тогда вы можете просто представить и отклонить свой обычай LoadingViewController обычно:

@IBAction func onSubmit(_ sender: Any) {

    // Present loading view controller.
    self.present(LoadingViewController(), animated: true)

    // Dismiss later in the callback of your API call...
    // API.request {
    //     self.dismiss(animated: true)
    // }
}

Это может достичь эффекта, который вы ищете:
custom transition demo

0 голосов
/ 17 ноября 2018

Вот решение, которое создаст простое представление загрузчика поверх представленного представления,

Сначала нам нужно создать класс, который отвечает за добавление / удаление activityIndicator

class AppLoaderView : UIView{

    fileprivate
    lazy var circularProgressIndicator : UIActivityIndicatorView = {
        let activityIndicator = UIActivityIndicatorView(frame: CGRect(x: 0, y: 0, width: 40, height: 40))
        activityIndicator.center = self.center
        activityIndicator.style = .gray
        activityIndicator.translatesAutoresizingMaskIntoConstraints = false
        activityIndicator.hidesWhenStopped = true
        self.addSubview(activityIndicator)
        return activityIndicator
    }()


    func showSpinning() {
        setupConstraints()
        circularProgressIndicator.startAnimating()
    }

    private
    func setupConstraints() {
        let xCenterConstraint = NSLayoutConstraint(item: self, attribute: .centerX,
                                                   relatedBy: .equal, toItem: circularProgressIndicator,
                                                   attribute: .centerX,
                                                   multiplier: 1,
                                                   constant: 0)
        self.addConstraint(xCenterConstraint)

        let yCenterConstraint = NSLayoutConstraint(item: self, attribute: .centerY,
                                                   relatedBy: .equal, toItem: circularProgressIndicator,
                                                   attribute: .centerY,
                                                   multiplier: 1,
                                                   constant: 0)
        self.addConstraint(yCenterConstraint)
    }


    func removeLoading() {
        circularProgressIndicator.stopAnimating()
    }

}

Теперь мы создадим расширение для viewController, которое имеет два метода: один для отображения LoaderView и один для его удаления,

extension UIViewController{

    private var loaderView : AppLoaderView?{

        if let view =  self.view.subviews.first(where: { $0 is AppLoaderView}) as? AppLoaderView { return view }
        let view = AppLoaderView(frame: self.view.frame)
        view.backgroundColor = .white
        view.autoresizingMask = [.flexibleHeight, .flexibleWidth]
        view.isHidden = true
        return view
    }


    func showLoaderView(){
        if let view = loaderView  {

            self.view.addSubview(view)
            self.view.bringSubviewToFront(view)
            view.isHidden = false
            view.clipsToBounds = true
            view.layoutIfNeeded()
            view.showSpinning()

        }

    }

    func removeLoaderView(){
        if let view = loaderView{
            view.removeLoading()
            view.removeFromSuperview()
            self.view.layoutIfNeeded()
        }
    }
}

Вот и все, теперь с вашим примером вы можете вызвать self.showLoaderView(), когда кнопка нажата, и как только вызов API вернется, вы вызовете self.removeLoaderView().

Добавьте их где-нибудь в своем проекте, и на любом viewController вы можете вызвать эти методы для show/hide вашего loaderView.

...