在另一个 ViewController 中的 ViewController 之间显示和切换

Posted

技术标签:

【中文标题】在另一个 ViewController 中的 ViewController 之间显示和切换【英文标题】:Displaying and switching between ViewControllers in another ViewController 【发布时间】:2018-12-28 15:08:40 【问题描述】:

我基本上是在尝试创建一个自定义的 UITabBarController,因为我需要一些特定的功能。 TabBar 本身已完成并正在工作,但我不太清楚如何在 CustomTabBarViewController 本身中显示 ViewControllers。

假设我有以下方法:

func tabSelected(_ index: Int) 

并且通过tabbar.frame.size知道我的TabBar的高度,我如何在TabBar上方实例化两个ViewController并在调用tabSelected方法时在它们之间切换?过渡动画会更好,但不是必需的。

注意:我的 TabBar 不继承自 UITabBarController,仅继承自常规 UIViewController,以避免进一步混淆。

【问题讨论】:

如何呈现 ViewControllers?你使用segues吗?你有 ViewControllers 数组并且你只是展示它们吗?你使用 Contrainer 视图吗? @RobertDresler 这就是我想要弄清楚的。我对 ios dev 很陌生,所以我不知道你将如何在另一个视图控制器中显示一个视图控制器,但我认为一个简单的容器不会做到这一点,因为你需要实例化两个视图控制器并在一个时间取决于当前选择的选项卡。在通常的 iOS TabBarController 中,这显然很容易,因为您只需将 segues 拖到您想要作为选项卡的相应视图控制器。 你使用 Storyboard 吗? @RobertDresler 好吧,是的,只是我的标签栏是我的“主”视图控制器中的一个简单 UIView,我现在要弄清楚的是如何在标签栏上方的主视图控制器中显示其他的 “子视图控制器”是这里的相关概念。 【参考方案1】:

在这里我创建了示例项目: CustomTabBarViewController


您应该有子 ViewControllers 的容器视图 那么你应该有嵌入 ViewControllers 的数组 你应该调用方法 CustomTabBarViewController 里面改变了 ViewController 从您作为此方法的参数传递的索引处的 VC 数组到 ViewController 的容器视图

首先为您的 TabBar 按钮声明插座集合,并获取容器视图的参考,您的 ViewController 将在其中显示

@IBOutlet var tabBarButtons: [UIButton]!
@IBOutlet weak var container: UIView!

然后为您的标签栏项目创建数组

var items: [UIViewController]?

接下来为你的控制器创建惰性变量

private lazy var aVC: A = 
    let storyboard = UIStoryboard(name: "Main", bundle: nil)
    return storyboard.instantiateViewController(withIdentifier: "a") as! A
()

private lazy var bVC: B = 
    let storyboard = UIStoryboard(name: "Main", bundle: nil)
    return storyboard.instantiateViewController(withIdentifier: "b") as! B
()

.... 这可以通过创建根据 VC 的标识符返回 ViewController 的方法来简化

之后将 ViewControllers 添加到您的 items 数组中,并且每个都添加为您的 TabBarViewController 的 child

override func viewDidLoad() 
    super.viewDidLoad()
    items = [aVC, bVC]
    items!.forEach  addChild($0) 

继续声明设置 ViewController 的方法

private func setViewController(_ viewController: UIViewController) 
    items!.forEach  $0.view.removeFromSuperview(); $0.willMove(toParent: nil) 
    container.addSubview(viewController.view)
    viewController.view.frame = container.bounds
    viewController.view.autoresizingMask = [.flexibleWidth, .flexibleHeight]
    viewController.didMove(toParent: self)

现在为您的标签栏按钮添加操作并获取按钮索引。然后用这个索引调用你的tabSelected 方法

@IBAction func buttonPressed(_ sender: UIButton) 
    if let index = tabBarButtons.index(of: sender) 
        tabSelected(index)
    

tabSelected 内部根据发送者标签栏按钮的索引从items 设置VC

func tabSelected(_ index: Int) 
    if let item = items?[index] 
        setViewController(item)
    

终于在viewDidLoad设置第一项

override func viewDidLoad() 
    ...
    tabSelected(0)


现在您可以完全自定义您的 ViewController 并制作您从 UITabBarController 知道的其他史诗般的东西

【讨论】:

我想你不太明白。我的自定义 TabBar 没有从 UITabBarController 继承,所以我需要完全复制它的视图切换机制。 @just_deko 检查已编辑的答案,如果有不清楚的地方,请随时提问。 :-) @just_deko 我创建了演示并将其推送到 GitHub 上。上面的链接在我的答案之上。【参考方案2】:

这是另一种方法:

1. 在您的 CustomTabBarViewController 中定义一个数组来保存 ViewController:

var viewControllers: [UIViewController]

实例化视图控制器并将它们添加到数组中:

// If you're not using storyboard:
let homeViewController = HomeViewController()
// If using storyboard:
let searchViewController = storyboard.instantiateViewController(withIdentifier: "SearchViewController")

viewControllers = [homeViewController, searchViewController, ...]

2.定义一个变量来跟踪被选中的标签按钮:

var selectedIndex: Int = 0

3. 像这样实现您的tabSelected 方法。我已经解释了代码中的每一行:

func tabSelected(_ index: Int) 
    let previousIndex = selectedIndex

    selectedIndex = index

    // Use previousIndex to access the previous ViewController from the viewControllers array.
    let previousVC = viewControllers[previousIndex]

    // Remove the previous ViewController
    previousVC.willMove(toParentViewController: nil)
    previousVC.view.removeFromSuperview()
    previousVC.removeFromParentViewController()

    // Use the selectedIndex to access the current ViewController from the viewControllers array.
    let vc = viewControllers[selectedIndex]

    // Add the new ViewController (Calls the viewWillAppear method of the ViewController you are adding)
    addChildViewController(vc)
    vc.view.frame = contentView.bounds

    // contentView is the main view above your tab buttons
    contentView.addSubview(vc.view)

    // Call the viewDidAppear method of the ViewController you are adding using didMove(toParentViewController: self)
    vc.didMove(toParentViewController: self)

【讨论】:

以上是关于在另一个 ViewController 中的 ViewController 之间显示和切换的主要内容,如果未能解决你的问题,请参考以下文章

根据用户选择将 UIPickerView 中的数据保存在 NSUserDefaults 中,并在另一个 ViewController Objective-C 中调用

如何在另一个 TabController 中选择 ViewController?

在另一个视图控制器中调用 uiviewcontroller 中的操作

通过在另一个 ViewController 中按下按钮/在另一个 ViewController 中引用 UITableView 创建 UITableViewCell

如何在另一个 ViewController 中将带有 Xib 的 ViewController 显示为 SubView

将一个 ViewController 部分呈现在另一个之上