Навигация по мульти-контроллеру в Swift - PullRequest
0 голосов
/ 30 октября 2018

Боковое меню навигации в Swift

Swift 4.2, Xcode 10.0

Моя конечная цель заключается в том, чтобы иметь возможность легко (обычно) перемещаться / перемещаться по моим контроллерам вида, как показано ниже.

Navigation

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

Path through storyboard

Уникальные пути контроллеров вида для отображения из бокового меню.

Animation Paths Примечание: каждый цвет на изображении выше - это еще один путь, по которому приложение может пойти после того, как что-то коснулось бокового меню.

В этой реализации так много всего плохого, что я даже не знаю, с чего начать. В редких случаях вы можете видеть содержимое промежуточного контроллера представления между сегментами. Кроме того, анимация может быть немного прерывистой и искаженной из-за количества сегментов, которое требуется для фактического перехода к целевому виду в некоторых случаях. Не говоря уже об огромной сложности и сложности, которая теперь требуется для добавления еще одной строки в мое боковое меню. И я прекрасно знаю, что это ужасно, и я отчаянно пытаюсь найти решение, а не мою сложную навигационную проблему. В последнее время я экспериментировал с использованием представлений контейнеров и размещением моего бокового меню внизу стека, а не сверху, как сейчас, но оно ни к чему не привело.


Последние несколько недель я сводил себя с ума, пытаясь выяснить, как это сделать. Я нашел бесчисленное множество реализаций боковых меню, но все, что я нашел к этой дате, будет показывать боковое меню только на одном контроллере вида вместо того, чтобы отображаться на всех объектах бокового меню и обрабатывать их, если они все на том же уровне так сказать. По сути, боковое меню должно быть в состоянии появиться на всех 3 контроллерах вида и устранить необходимость хакерского перехода через контроллер вида. Также было бы идеально, если бы это боковое меню легко масштабировалось, чтобы я мог с легкостью добавить несколько разделов в боковое меню.


Ответы [ 2 ]

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

enter image description here

Я создал пример проекта для этого вопроса. Вы можете увидеть результат на изображении выше. По сути, я создал класс-оболочку для боковой панели, а затем использовал его всякий раз, когда захочу:)

Боковая панель

import UIKit
protocol SidebarDelegate {
    func sidbarDidOpen()
    func sidebarDidClose(with item: Int?)
}
class SidebarLauncher: NSObject{

    var view: UIView?
    var delegate: SidebarDelegate?
    var vc: NavigationViewController?
    init(delegate: SidebarDelegate) {
        super.init()
        self.delegate = delegate
    }

    func show(){
        let bounds = UIScreen.main.bounds
        let v = UIView(frame: CGRect(x: -bounds.width, y: 0, width: bounds.width, height: bounds.height))
        v.backgroundColor = .clear
        let vc = UIStoryboard.init(name: "Main", bundle: nil).instantiateViewController(withIdentifier: "NavigationController") as! NavigationViewController
        v.addSubview(vc.view)
        vc.view.translatesAutoresizingMaskIntoConstraints = false
        NSLayoutConstraint.activate([
            vc.view.topAnchor.constraint(equalTo: v.topAnchor),
            vc.view.leadingAnchor.constraint(equalTo: v.leadingAnchor),
            vc.view.bottomAnchor.constraint(equalTo: v.bottomAnchor),
            vc.view.trailingAnchor.constraint(equalTo: v.trailingAnchor, constant: -60)
            ])
        vc.delegate = self
        v.isUserInteractionEnabled = true
        v.addGestureRecognizer(UITapGestureRecognizer(target: self, action: #selector(handleTapGesture(_:))))
        self.view = v
        self.vc = vc
        UIApplication.shared.keyWindow?.addSubview(v)

        UIView.animate(withDuration: 0.5, delay: 0, usingSpringWithDamping: 1, initialSpringVelocity: 1, options: [.curveEaseOut], animations: {
            self.view?.frame = CGRect(x: 0, y: 0, width: self.view!.frame.width, height: self.view!.frame.height)
            self.view?.backgroundColor = UIColor.black.withAlphaComponent(0.5)
        }, completion: {completed in
            self.delegate?.sidbarDidOpen()
        })

    }

    @objc func handleTapGesture(_ sender: UITapGestureRecognizer){
        closeSidebar(option: nil)
    }
    func closeSidebar(option: Int?){
        UIView.animate(withDuration: 0.5, delay: 0, usingSpringWithDamping: 1, initialSpringVelocity: 1, options: [.curveEaseOut], animations: {
            if let view = self.view{
                view.frame = CGRect(x: -view.frame.width, y: 0, width: view.frame.width, height: view.frame.height)
                self.view?.backgroundColor = .clear

            }
        }, completion: {completed in
            self.view?.removeFromSuperview()
            self.view = nil
            self.vc = nil
            self.delegate?.sidebarDidClose(with: option)
        })
    }

}
extension SidebarLauncher: NavigationDelegate{
    func navigation(didSelect: Int?) {
        closeSidebar(option: didSelect)
    }
}

NavigationController

import UIKit
protocol NavigationDelegate{
    func navigation(didSelect: Int?)
}

class NavigationViewController: UIViewController{

    @IBOutlet weak var buttonLaunchVC: UIButton!
    @IBOutlet weak var buttonSecondViewController: UIButton!
    @IBOutlet weak var buttonThirdViewController: UIButton!


    var delegate: NavigationDelegate?

    override func viewDidLoad() {
        super.viewDidLoad()
        [buttonLaunchVC,buttonSecondViewController,buttonThirdViewController].forEach({
            $0?.addTarget(self, action: #selector(didSelect(_:)), for: .touchUpInside)
        })
    }

    @objc func didSelect(_ sender: UIButton){
        switch sender {
        case buttonLaunchVC:
            delegate?.navigation(didSelect: 0)
        case buttonSecondViewController:
            delegate?.navigation(didSelect: 1)
        case buttonThirdViewController:
            delegate?.navigation(didSelect: 2)
        default:
            break
        }
    }


    @IBAction func CloseMenu(_ sender: Any) {
        delegate?.navigation(didSelect: nil)
    }


}

ViewController

class ViewController: UIViewController {

    @IBAction func OpenMenu(_ sender: Any) {
        SidebarLauncher(delegate: self ).show()
    }

}
extension ViewController: SidebarDelegate{
    func sidbarDidOpen() {
        print("Sidebar opened")
    }

    func sidebarDidClose(with item: Int?) {
        guard let item = item else {return}
        print("Did select \(item)")
        switch item {
        case 0:
           break
        case 1:
            let v = UIStoryboard.main.SecondVC()
            present(v!, animated: true)
        case 2:
            let v = UIStoryboard.main.ThirdVC()
            present(v!, animated: true)
        default:
            break
        }
    }

Основная область интересов SidebarLauncher класс что он делает: когда вы вызываете метод show () . он создает UIView, затем добавляет его в окно ключей (т. е. текущий вид) и после этого добавляет NavigationController.

Чтобы настроить связь с боковой панелью, я создал два протокола

  1. SidebarDelegate:

Делегат боковой панели - это основной протокол, с помощью которого вы узнаете, выбрал ли пользователь какой-либо ViewController или нет.

  1. NavigationDelegate: этот протокол используется для связи между оболочкой и контроллером навигации. Когда пользователь нажимает любую кнопку. это сообщает классу обёртки об этом.

Класс-оболочка имеет метод closeSidebar , который затем закрывает боковую панель и сообщает классу Controller, что боковая панель закрыта с опцией.

В sidebarDidClose вы можете решить, что делать с выбором, сделанным пользователем.

Я немного торопился, поэтому я использовал Int , тогда как вы должны рассмотреть возможность использования struct или class, в зависимости от того, что вам нужно, чтобы определить, какой ViewController открыть.

https://github.com/sahilmanchanda2/SidebarTest

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...