WedX - журнал о программировании и компьютерных науках

iOS - стекировать полноэкранный viewController при представлении другого viewController

У меня есть UITabBarViewController с двумя вкладками. Я хочу представить полноэкранный режим viewController на одной из вкладок. Для этого я использовал следующий код.

    let navCtrl = UINavigationController(rootViewController: eventViewController)
    navCtrl.modalPresentationStyle = .fullScreen        
    self.navigationController?.present(navCtrl, animated: true)

Оно работает. И EventViewController в полноэкранном режиме. Однако при представлении другого viewController в EventViewController EventViewController по-прежнему отображается в полноэкранном режиме. Но я хочу, чтобы он уменьшался в размерах и складывался, как обычно (как на изображении). Для этого я изменил modalPresentationStyle на overCurrentContext.

    let navCtrl = UINavigationController(rootViewController: eventViewController)
    navCtrl.modalPresentationStyle = .overCurrentContext        
    self.navigationController?.present(navCtrl, animated: true)

Это так, но это вызывает другую проблему: если я меняю вкладки и закрываю EventViewController, представляющим viewController является black, как описано в этом вопрос (ни один из ответов не помог).


введите здесь описание изображения

В основном я хочу, чтобы EventController был полноэкранным, но уменьшался в размере при представлении в нем другого контроллера. Как это сделать?

Обновлять

Простой проект с той же проблемой.

class TabBarController: UITabBarController {

    override func viewDidLoad() {
        super.viewDidLoad()
        let ctrl = TabZeroViewController()
        ctrl.tabBarItem.image = UIImage(named: "archived-task")
        ctrl.tabBarItem.title = "One"


        let test = TabOneViewController()
        test.tabBarItem.image = UIImage(named: "Test")
        test.tabBarItem.title = "Test"

        let tabBarList = [ctrl, test ]

        self.viewControllers = tabBarList.map {
            let nav = UINavigationController(rootViewController: $0)
            nav.interactivePopGestureRecognizer?.isEnabled = true
            return nav
        }
    }
}



class TabZeroViewController: UITableViewController {


    override func viewDidLoad() {
        super.viewDidLoad()
        self.tableView.delegate = self
        self.tableView.dataSource = self

        self.view.backgroundColor = .white
    }

    override func numberOfSections(in tableView: UITableView) -> Int {
        return 1
    }

    override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
        return 10
    }

    override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
        let cell =  UITableViewCell()
        cell.textLabel?.text = "\(indexPath.row)"
        return cell
    }

    override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
        let ctrl = ModalTableViewController()

        let nav = UINavigationController(rootViewController: ctrl)
        nav.modalPresentationStyle = .fullScreen

        self.navigationController?.present(nav, animated: true)
    }

}

class ModalTableViewController: UITableViewController {
    override func viewDidLoad() {
        self.view.backgroundColor = .red
        let button = UIButton()
        button.setTitle("Cancel", for: .normal)
        button.addTarget(self, action: #selector(dismissModal), for: .allEvents)
        let item = UIBarButtonItem()
        item.customView = button
        self.navigationItem.leftBarButtonItem = item
        self.tableView.dataSource = self
        self.tableView.delegate = self
    }

    @objc func dismissModal() {
        self.dismiss(animated: true, completion: nil)
    }


    override func numberOfSections(in tableView: UITableView) -> Int {
        return 1
    }

    override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
        return 10
    }

    override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
        let cell =  UITableViewCell()
        cell.textLabel?.text = "Event"
        return cell
    }

    override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
        let ctrl = EventViewController()
        let nav = UINavigationController(rootViewController: ctrl)
         nav.modalPresentationStyle = .overCurrentContext
        self.navigationController?.present(nav, animated: true)
    }
}


class TabOneViewController: UIViewController {

    override func viewDidLoad() {
        super.viewDidLoad()

    }
}




class EventViewController: UITableViewController {

    override func viewDidLoad() {
        self.view.backgroundColor = .red
        let button = UIButton()
        button.setTitle("Cancel", for: .normal)
        button.addTarget(self, action: #selector(dismissModal), for: .allEvents)
        let item = UIBarButtonItem()
        item.customView = button
        self.navigationItem.leftBarButtonItem = item
        self.tableView.dataSource = self
        self.tableView.delegate = self
    }

    @objc func dismissModal() {
        self.dismiss(animated: true, completion: nil)
    }


    override func numberOfSections(in tableView: UITableView) -> Int {
        return 1
    }

    override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
        return 10
    }

    override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
        let cell =  UITableViewCell()
        cell.textLabel?.text = "Event"
        return cell
    }

    override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
        let ctrl = EventViewController()
        let nav = UINavigationController(rootViewController: ctrl)
        self.navigationController?.present(nav, animated: true)
    }
}

Добавьте этот код в willConnectTo из SceneDelegate.

 if let windowScene = scene as? UIWindowScene {
        let window = UIWindow(windowScene: windowScene)
        window.rootViewController = TabBarController()
        self.window = window
        window.makeKeyAndVisible()
    }

Пока вы находитесь на первой вкладке, выберите ячейку таблицы, чтобы открыть файл ModalTableViewController. А затем переключитесь на вкладки и закройте ModalTableViewController.


  • Прежде всего, вам нужно обновить, что в навигационном контроллере вы представляете контроллер представления, но навигационный контроллер предназначен для использования для нажатия контроллеров представления. Так как это может вызвать неожиданное поведение. 24.02.2020
  • Я запустил тот же поток, и он работает так, как ожидалось. Один вопрос: навигационный контроллер, который имеет EventViewController в качестве корня, не отображается на весь экран, как вы можете менять вкладки во время его отображения. Пожалуйста, проясните мне этот момент. 26.02.2020
  • Вы представили навигационный контроллер, и когда вы отключаете любой контроллер, который не отключает подключенный навигационный контроллер, вот почему вы сталкиваетесь с проблемой Черный экран. 27.02.2020
  • @neerajjoshi, выполните следующие действия: 1. установите modalPresentationStyle = .overCurrentContext 2. текущий видCtrl 3. выберите другую вкладку, а затем выберите ту же вкладку. 4 закрыть представленный видCtrl. 28.02.2020
  • @mahan, могу я поиграть с твоим исходным кодом? Если да, то вы можете создать пример проекта с таким сценарием и загрузить его на GitHub. 03.03.2020
  • @ШармаВишал. Не могу этого сделать по кадровым причинам. Однако я включил весь код простого проекта, чтобы вы могли протестировать его, если хотите. 03.03.2020
  • @NajeeburRehman Я добавляю больше кода. Если хотите, можете попробовать сами. 03.03.2020
  • Также сохраняйте контекст экрана перед нажатием или представлением 04.03.2020
  • Не могли бы вы добавить свое решение? @AbhishekMaurya 04.03.2020
  • @mahan Я пробовал код, которым вы поделились, но для меня он работает нормально. У меня не черный экран. Вот ссылка на видео, как этот код работает для меня share.getcloudapp.com/nOuNDOE4 04.03.2020
  • @mahan есть что-то, что я не правильно понимаю в твоих ожиданиях? 04.03.2020

Ответы:


1

Как, например, в проекте - при просмотре в полноэкранном режиме TabBar скрывается. Но я немного изменил код, чтобы предложить рабочее решение. Возможно, вы хотели бы немного изменить его, но я надеюсь, что это подтолкнет вас в правильном направлении :)

На самом деле нужно было отклонить ModalTableViewController, чтобы избежать черного экрана.

class TabBarController: UITabBarController {

    override func viewDidLoad() {
        super.viewDidLoad()
        let ctrl = TabZeroViewController()
        ctrl.tabBarItem.image = UIImage(named: "archived-task")
        ctrl.tabBarItem.title = "One"


        let test = TabOneViewController()
        test.tabBarItem.image = UIImage(named: "Test")
        test.tabBarItem.title = "Test"

        let tabBarList = [ctrl, test ]

        let viewControllers: [UIViewController] = tabBarList.map {
            let nav = UINavigationController(rootViewController: $0)
            nav.interactivePopGestureRecognizer?.isEnabled = true
            nav.tabBarItem = $0.tabBarItem
            return nav
        }

        self.setViewControllers(viewControllers, animated: false)
    }

    override var selectedViewController: UIViewController? {
        get {return super.selectedViewController}
        set {
            if super.selectedViewController?.presentedViewController != nil {
                super.selectedViewController?.dismiss(animated: false, completion: nil)
            }
            super.selectedViewController = newValue
        }
    }
}



class TabZeroViewController: UITableViewController {


    override func viewDidLoad() {
        super.viewDidLoad()
        self.tableView.delegate = self
        self.tableView.dataSource = self

        self.view.backgroundColor = .white
    }

    override func numberOfSections(in tableView: UITableView) -> Int {
        return 1
    }

    override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
        return 10
    }

    override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
        let cell =  UITableViewCell()
        cell.textLabel?.text = "\(indexPath.row)"
        return cell
    }

    override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
        let ctrl = ModalTableViewController()

        let nav = UINavigationController(rootViewController: ctrl)
        nav.modalPresentationStyle = .currentContext

        self.present(nav, animated: true)
    }

}

class ModalTableViewController: UITableViewController {
    override func viewDidLoad() {
        self.view.backgroundColor = .red
        let button = UIButton()
        button.setTitle("Cancel", for: .normal)
        button.addTarget(self, action: #selector(dismissModal), for: .allEvents)
        let item = UIBarButtonItem()
        item.customView = button
        self.navigationItem.leftBarButtonItem = item
        self.tableView.dataSource = self
        self.tableView.delegate = self
    }

    @objc func dismissModal() {
        self.presentingViewController?.dismiss(animated: false, completion: nil)
    }


    override func numberOfSections(in tableView: UITableView) -> Int {
        return 1
    }

    override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
        return 10
    }

    override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
        let cell =  UITableViewCell()
        cell.textLabel?.text = "Event"
        return cell
    }

    override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
        let ctrl = EventViewController()
        let nav = UINavigationController(rootViewController: ctrl)
         nav.modalPresentationStyle = .fullScreen
        self.navigationController?.present(nav, animated: true)
    }
}


class TabOneViewController: UIViewController {

    override func viewDidLoad() {
        super.viewDidLoad()
        view.backgroundColor = .white
    }
}




class EventViewController: UITableViewController {

    override func viewDidLoad() {
        self.view.backgroundColor = .red
        let button = UIButton()
        button.setTitle("Cancel", for: .normal)
        button.addTarget(self, action: #selector(dismissModal), for: .allEvents)
        let item = UIBarButtonItem()
        item.customView = button
        self.navigationItem.leftBarButtonItem = item
        self.tableView.dataSource = self
        self.tableView.delegate = self
    }

    @objc func dismissModal() {
        self.dismiss(animated: true, completion: nil)
    }


    override func numberOfSections(in tableView: UITableView) -> Int {
        return 1
    }

    override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
        return 10
    }

    override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
        let cell =  UITableViewCell()
        cell.textLabel?.text = "Event"
        return cell
    }

    override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
        let ctrl = EventViewController()
        let nav = UINavigationController(rootViewController: ctrl)
        self.navigationController?.present(nav, animated: true)
    }
}

Удачи!

04.03.2020

2

Попробуйте этот код для отображения экрана модально:

 func getImageFromView() -> UIImage {

        let layer = UIApplication.shared.keyWindow?.layer
        let scale = UIScreen.main.scale
        UIGraphicsBeginImageContextWithOptions(layer?.frame.size ?? CGSize.zero, false, scale)
        if let context = UIGraphicsGetCurrentContext() {
            layer?.render(in: context)
            let image = UIGraphicsGetImageFromCurrentImageContext()
            UIGraphicsEndImageContext()
            return image ?? UIImage()
        }
        return UIImage()
    }


/// This is the method to present  screen modally
/// - parameter controller: controller instance on which screen will be presented
func presentScreenModally(controller: UIViewController, animated: Bool) {
    let loginController  = UIStoryboard.loadLoginViewController()//Get instance of controller form storyboard
    loginController.bgTranParentImg = getImageFromView()

    let bgImage = getImageFromView()
    let presentationStyleViewController = UIStoryboard.loadPresentationStyleController()// This is another controller, which I am pasting below
    presentationStyleViewController.bgimage = bgImage
    presentationStyleViewController.loginController = loginController
    presentationStyleViewController.addChild(loginController)
    controller.view.window?.addSubview(presentationStyleViewController.view)
    loginController.view.frame = presentationStyleViewController.containerView.bounds
    presentationStyleViewController.containerView.addSubview(loginController.view)

    let navigationController = UINavigationController(rootViewController: presentationStyleViewController)
    navigationController.navigationBar.isHidden = true
    navigationController.modalPresentationStyle = .fullScreen
    controller.navigationController?.present(navigationController, animated: animated, completion: nil)
}

Класс PresentationStyleViewController:

class PresentationStyleViewController: UIViewController {

    @IBOutlet var containerView: UIView!
    @IBOutlet var containeTopConstraint: NSLayoutConstraint!
    @IBOutlet var containerBottomConstraint: NSLayoutConstraint!
    @IBOutlet var backgroundImage: UIImageView!

    var bgimage: UIImage?
    let topPadding: CGFloat = 30
    var loginController: LoginViewController?

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

    override func viewDidAppear(_ animated: Bool) {
        restorePopup()
    }

    /// Initial UI setup
    func uiSetup() {
        containeTopConstraint.constant = self.view.frame.size.height
        backgroundImage.image = bgimage
    }

    @IBAction func panGesture(_ sender: UIPanGestureRecognizer) {
        guard let piece = sender.view else {return}
        let translation = sender.translation(in: piece.superview)
        containeTopConstraint.constant = translation.y >= topPadding ? translation.y : topPadding

        if sender.state == .ended || sender.state == .cancelled {
            if containeTopConstraint.constant > self.view.frame.size.height/4 && translation.y > 0 {
                self.dismissPopup()
            } else {
                self.restorePopup()
            }
        }
    }

    /// Dismisses popup and controller
    func dismissPopup() {
        containeTopConstraint.constant = self.view.frame.size.height
        UIView.animate(withDuration: 0.3,
                       animations: {
                        self.view.layoutIfNeeded()
        }, completion: { (_) in
            self.loginController?.btnClick_cross(UIButton())
            self.dismiss(animated: false)
        })
    }

    /// Restores popup at initial position
    func restorePopup() {
        containeTopConstraint.constant = topPadding
        UIView.animate(withDuration: 0.3,
                       animations: {
                        self.view.layoutIfNeeded()
        }, completion: nil)
    }
}
04.03.2020
Новые материалы

Как проанализировать работу вашего классификатора?
Не всегда просто знать, какие показатели использовать С развитием глубокого обучения все больше и больше людей учатся обучать свой первый классификатор. Но как только вы закончите..

Работа с цепями Маркова, часть 4 (Машинное обучение)
Нелинейные цепи Маркова с агрегатором и их приложения (arXiv) Автор : Бар Лайт Аннотация: Изучаются свойства подкласса случайных процессов, называемых дискретными нелинейными цепями Маркова..

Crazy Laravel Livewire упростил мне создание электронной коммерции (панель администратора и API) [Часть 3]
Как вы сегодня, ребята? В этой части мы создадим CRUD для данных о продукте. Думаю, в этой части я не буду слишком много делиться теорией, но чаще буду делиться своим кодом. Потому что..

Использование машинного обучения и Python для классификации 1000 сезонов новичков MLB Hitter
Чему может научиться машина, глядя на сезоны новичков 1000 игроков MLB? Это то, что исследует это приложение. В этом процессе мы будем использовать неконтролируемое обучение, чтобы..

Учебные заметки: создание моего первого пакета Node.js
Это мои обучающие заметки, когда я научился создавать свой самый первый пакет Node.js, распространяемый через npm. Оглавление Глоссарий I. Новый пакет 1.1 советы по инициализации..

Забудьте о Matplotlib: улучшите визуализацию данных с помощью умопомрачительных функций Seaborn!
Примечание. Эта запись в блоге предполагает базовое знакомство с Python и концепциями анализа данных. Привет, энтузиасты данных! Добро пожаловать в мой блог, где я расскажу о невероятных..

ИИ в аэрокосмической отрасли
Каждый полет – это шаг вперед к великой мечте. Чтобы это происходило в их собственном темпе, необходима команда астронавтов для погони за космосом и команда технического обслуживания..


Для любых предложений по сайту: [email protected]