【问题标题】:How to open a embedded segue controller from another controller?如何从另一个控制器打开嵌入式 segue 控制器?
【发布时间】:2020-01-20 11:41:27
【问题描述】:

我正在按照与此应用 https://github.com/Bailig/SurveyApp 相同的设计方法制作应用。

在上面的 GitHub 项目中,控制器的设计方式类似于带有 ContainerView 的普通 ViewController。而且这个普通的 ViewController 是 Embed Segue 与第一个控制器或第一页。所有后续屏幕的容器视图都将被替换。
在上面的项目中,最后有一个感谢页面,在我的应用程序中,我在感谢页面上放置了一个按钮。我想通过点击感谢页面中的按钮再次打开第一页。如何从最后一页控制器/FourthController 执行此操作?

视图控制器

class ViewController: UIViewController {

var currentController: UIViewController?
var pageIndex = 1
var survey = Survey()

@IBOutlet weak var backButton: UIButton!
@IBOutlet weak var nextButton: UIButton!
@IBOutlet weak var containerView: UIView!
@IBOutlet weak var progressLabel: UILabel!
@IBAction func nextTapped(_ sender: Any) {
    switch pageIndex {
    case 1:
        let nextController = storyboard?.instantiateViewController(withIdentifier: "SecondController")
        if let fromController = currentController, let toController = nextController as? SecondController {
            toController.survey = survey
            moveAndSizeChildControllers(fromController: fromController, toController: toController)
            pageIndex += 1
            setButtonAndProgressLabel()
        }
    case 2:
        let nextController = storyboard?.instantiateViewController(withIdentifier: "ThirdController")
        if let fromController = currentController, let toController = nextController as? ThirdController {
            toController.survey = survey
            moveAndSizeChildControllers(fromController: fromController, toController: toController)
            pageIndex += 1
            setButtonAndProgressLabel()
        }
    case 3:
        let nextController = storyboard?.instantiateViewController(withIdentifier: "FourthController")
        if let fromController = currentController, let toController = nextController as? FourthController {
            toController.survey = survey
            moveAndSizeChildControllers(fromController: fromController, toController: toController)
            pageIndex += 1
            setButtonAndProgressLabel()
        }
    default:
        break
    }
}
@IBAction func backTapped(_ sender: Any) {
    switch pageIndex {
    case 2:
        let nextController = storyboard?.instantiateViewController(withIdentifier: "FirstController")
        if let fromController = currentController, let toController = nextController as? FirstController {
            toController.survey = survey
            moveAndSizeChildControllers(fromController: fromController, toController: toController)
            pageIndex -= 1
            setButtonAndProgressLabel()
        }
    case 3:
        let nextController = storyboard?.instantiateViewController(withIdentifier: "SecondController")
        if let fromController = currentController, let toController = nextController as? SecondController {
            toController.survey = survey
            moveAndSizeChildControllers(fromController: fromController, toController: toController)
            pageIndex -= 1
            setButtonAndProgressLabel()
        }
    default:
        break
    }
}

@IBOutlet weak var backTapped: UIButton!

override func viewDidLoad() {
    super.viewDidLoad()

}

override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
    currentController = segue.destination
    if let firstController = currentController as? FirstController {
        firstController.survey = survey
    }
    setButtonAndProgressLabel()
}

func moveAndSizeChildControllers(fromController: UIViewController, toController: UIViewController) {
    fromController.willMove(toParentViewController: nil)

    toController.view.frame = containerView.bounds

    addChildViewController(toController)
    containerView.addSubview(toController.view)

    // animatin
    toController.view.alpha = 0
    UIView.animate(withDuration: 0.5, animations: { 
        toController.view.alpha = 1
        fromController.view.alpha = 0 
    }) { (completed) in
        fromController.view.removeFromSuperview()
        fromController.removeFromParentViewController()

        toController.didMove(toParentViewController: self)
        self.currentController = toController
    }
}
}

【问题讨论】:

    标签: ios swift uiviewcontroller segue uistoryboardsegue


    【解决方案1】:

    您可以使用通知管理它

    在 ViewController 中添加(主)

    override func viewDidLoad() {
        super.viewDidLoad()
    
        NotificationCenter.default.addObserver(self, selector: #selector(navigateToFirstPage), name:NSNotification.Name(rawValue:"NavigateToFirstPage") , object: nil)
    }
    
    @objc private func navigateToFirstPage() {
    
        pageIndex = 2
        self.backTapped(UIButton())
    }
    

    添加你的第四个ViewController

    // This is your button from where you need to perform action
    @IBAction func thanksButtonAction(_ sender: Any) {
    
         NotificationCenter.default.post(name: NSNotification.Name(rawValue:"NavigateToFirstPage"), object: nil)
    }
    

    【讨论】:

    • 感谢您的回答,这是实现我正在寻找的最简单的方法。
    【解决方案2】:

    我最好使用delegation pattern。它易于管理且易于理解。

    在FourthController 顶部导入后需要添加

    protocol FourthControllerThankDelegate {
        func didTapYourButton()
    }
    

    然后在该类中添加变量

    class FourthController: UIViewController {
    
        weak var delegate: FourthControllerThankDelegate?
        ...
    }
    

    那么您需要在按钮操作处理程序中调用 didTapYourButton()

    @IBAction func thanksButtonTapped(_ sender: Any) {
        delegate?.didTapYourButton()
    }
    

    然后在 ViewController 函数中 nextTapped: 你需要将此视图控制器设置为 FourthController 的委托

    case 3:
         ... // I have skipped code above 
         toController.delegate = self
         setButtonAndProgressLabel()
    }
    

    最后你需要处理委托操作

    extension ViewController: FourthControllerThankDelegate {
        func didTapYoutButton {
            pageIndex = 2
            backTapped(self)
        }
    }
    

    当您这样做时,backTapped 处理程序会将您移动到第一页。这不是退后的最佳方式。为了改善这一点,您可以创建一个函数“displayMeFirstPage”并将部分逻辑从 backTapped() case: 2 移到那里,并在该案例和委托处理程序内部调用它。有很多方法可以改善导航。如果您有任何问题,请告诉我。

    【讨论】:

    • @Pavel 感谢您的回答,伙计。您的方法和 Rohit 的方法都可以正常工作。您正在使用委托,而 Rohit 正在使用通知。我对我应该接受谁的答案感到困惑。
    • @KunduriRaj 对于目前的情况,NotificationCenter 看起来很合适(代码更少且易于集成),但在您的职业生涯中不会使用 NotificationCenter,因为它使项目难以调试且易于制作错误。你只会用它来收听系统消息,除非你不能这样做的困难情况。决定权在你。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-08-15
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-09-07
    相关资源
    最近更新 更多