You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何使用MDCTabBar?已开发应用但不知配置childView

嘿,我帮你梳理下MDCTabBar配置childView的两种常用方案,都是实际项目里验证过的,你可以根据自己的需求选:

方案一:搭配UIPageViewController实现滑动联动(推荐)

这种方式能让TabBar和页面滑动完美联动,体验更流畅,也是Material Design推荐的交互模式。步骤如下:

  1. 配置MDCTabBar并设置代理:先把TabBar的items配置好,然后设置它的代理来监听选中事件。
  2. 初始化UIPageViewController:把它作为子控制器加到你的容器视图中,负责管理所有子页面的切换。
  3. 关联TabBar和PageViewController:TabBar选中时切换PageViewController的页面,同时PageViewController滑动时同步更新TabBar的选中状态。

下面是完整的Swift代码示例:

import MaterialComponents.MaterialTabs

class MainViewController: UIViewController, MDCTabBarDelegate, UIPageViewControllerDataSource, UIPageViewControllerDelegate {
    private let tabBar = MDCTabBar()
    private var pageViewController: UIPageViewController!
    // 准备好和TabBar items对应的子控制器数组
    private let childVCs: [UIViewController] = [
        HomeViewController(),
        DiscoverViewController(),
        ProfileViewController()
    ]
    
    override func viewDidLoad() {
        super.viewDidLoad()
        setupTabBarLayout()
        setupPageViewController()
    }
    
    private func setupTabBarLayout() {
        // 配置TabBar的选项卡
        tabBar.items = [
            UITabBarItem(title: "首页", image: UIImage(named: "home"), tag: 0),
            UITabBarItem(title: "发现", image: UIImage(named: "discover"), tag: 1),
            UITabBarItem(title: "我的", image: UIImage(named: "profile"), tag: 2)
        ]
        tabBar.delegate = self
        tabBar.autoresizingMask = [.flexibleWidth, .flexibleTopMargin]
        tabBar.sizeToFit()
        view.addSubview(tabBar)
        
        // 用AutoLayout固定TabBar在顶部
        tabBar.translatesAutoresizingMaskIntoConstraints = false
        NSLayoutConstraint.activate([
            tabBar.topAnchor.constraint(equalTo: view.safeAreaLayoutGuide.topAnchor),
            tabBar.leadingAnchor.constraint(equalTo: view.leadingAnchor),
            tabBar.trailingAnchor.constraint(equalTo: view.trailingAnchor)
        ])
    }
    
    private func setupPageViewController() {
        // 初始化PageViewController,设置滑动过渡样式
        pageViewController = UIPageViewController(transitionStyle: .scroll, navigationOrientation: .horizontal, options: nil)
        pageViewController.dataSource = self
        pageViewController.delegate = self
        
        // 设置初始显示的页面
        pageViewController.setViewControllers([childVCs[0]], direction: .forward, animated: false, completion: nil)
        
        // 将PageViewController添加到当前控制器
        addChild(pageViewController)
        view.addSubview(pageViewController.view)
        pageViewController.didMove(toParent: self)
        
        // 布局PageViewController的视图在TabBar下方
        pageViewController.view.translatesAutoresizingMaskIntoConstraints = false
        NSLayoutConstraint.activate([
            pageViewController.view.topAnchor.constraint(equalTo: tabBar.bottomAnchor),
            pageViewController.view.leadingAnchor.constraint(equalTo: view.leadingAnchor),
            pageViewController.view.trailingAnchor.constraint(equalTo: view.trailingAnchor),
            pageViewController.view.bottomAnchor.constraint(equalTo: view.bottomAnchor)
        ])
    }
    
    // MARK: - MDCTabBarDelegate
    func tabBar(_ tabBar: MDCTabBar, didSelect item: UITabBarItem) {
        guard let selectedIndex = tabBar.items?.firstIndex(of: item) else { return }
        // 根据选中索引判断滑动方向
        let direction: UIPageViewController.NavigationDirection = selectedIndex > tabBar.selectedItemIndex ? .forward : .reverse
        pageViewController.setViewControllers([childVCs[selectedIndex]], direction: direction, animated: true, completion: nil)
    }
    
    // MARK: - UIPageViewControllerDataSource
    func pageViewController(_ pageViewController: UIPageViewController, viewControllerBefore viewController: UIViewController) -> UIViewController? {
        guard let index = childVCs.firstIndex(of: viewController), index > 0 else { return nil }
        return childVCs[index - 1]
    }
    
    func pageViewController(_ pageViewController: UIPageViewController, viewControllerAfter viewController: UIViewController) -> UIViewController? {
        guard let index = childVCs.firstIndex(of: viewController), index < childVCs.count - 1 else { return nil }
        return childVCs[index + 1]
    }
    
    // MARK: - UIPageViewControllerDelegate
    func pageViewController(_ pageViewController: UIPageViewController, didFinishAnimating finished: Bool, previousViewControllers: [UIViewController], transitionCompleted completed: Bool) {
        // 滑动结束后同步更新TabBar的选中状态
        guard completed, let currentVC = pageViewController.viewControllers?.first, let index = childVCs.firstIndex(of: currentVC) else { return }
        tabBar.setSelectedItemIndex(index, animated: true)
    }
}
方案二:直接管理子视图的显示隐藏(适合简单场景)

如果你的场景不需要滑动切换页面,只需要点击TabBar切换静态视图,这种方式更简单:

  1. 创建容器视图:用来承载所有子视图。
  2. 添加所有子视图到容器:初始状态下只显示第一个视图,其余隐藏。
  3. 监听TabBar选中事件:切换时隐藏当前视图,显示对应索引的视图。

代码示例:

import MaterialComponents.MaterialTabs

class SimpleTabViewController: UIViewController, MDCTabBarDelegate {
    private let tabBar = MDCTabBar()
    private let containerView = UIView()
    private var childViews: [UIView] = []
    
    override func viewDidLoad() {
        super.viewDidLoad()
        setupTabBar()
        setupContainer()
        setupChildViews()
    }
    
    private func setupTabBar() {
        tabBar.items = [
            UITabBarItem(title: "视图A", image: nil, tag: 0),
            UITabBarItem(title: "视图B", image: nil, tag: 1)
        ]
        tabBar.delegate = self
        tabBar.selectedItemIndex = 0
        view.addSubview(tabBar)
        
        // TabBar布局约束
        tabBar.translatesAutoresizingMaskIntoConstraints = false
        NSLayoutConstraint.activate([
            tabBar.topAnchor.constraint(equalTo: view.safeAreaLayoutGuide.topAnchor),
            tabBar.leadingAnchor.constraint(equalTo: view.leadingAnchor),
            tabBar.trailingAnchor.constraint(equalTo: view.trailingAnchor)
        ])
    }
    
    private func setupContainer() {
        view.addSubview(containerView)
        containerView.translatesAutoresizingMaskIntoConstraints = false
        NSLayoutConstraint.activate([
            containerView.topAnchor.constraint(equalTo: tabBar.bottomAnchor),
            containerView.leadingAnchor.constraint(equalTo: view.leadingAnchor),
            containerView.trailingAnchor.constraint(equalTo: view.trailingAnchor),
            containerView.bottomAnchor.constraint(equalTo: view.bottomAnchor)
        ])
    }
    
    private func setupChildViews() {
        // 创建两个示例子视图
        let viewA = UIView()
        viewA.backgroundColor = .systemTeal
        let viewB = UIView()
        viewB.backgroundColor = .systemPink
        
        childViews = [viewA, viewB]
        
        // 将子视图添加到容器并布局
        for view in childViews {
            view.translatesAutoresizingMaskIntoConstraints = false
            containerView.addSubview(view)
            NSLayoutConstraint.activate([
                view.topAnchor.constraint(equalTo: containerView.topAnchor),
                view.leadingAnchor.constraint(equalTo: containerView.leadingAnchor),
                view.trailingAnchor.constraint(equalTo: containerView.trailingAnchor),
                view.bottomAnchor.constraint(equalTo: containerView.bottomAnchor)
            ])
            // 默认隐藏所有视图
            view.isHidden = true
        }
        
        // 显示第一个视图
        childViews[0].isHidden = false
    }
    
    // MARK: - MDCTabBarDelegate
    func tabBar(_ tabBar: MDCTabBar, didSelect item: UITabBarItem) {
        guard let selectedIndex = tabBar.items?.firstIndex(of: item) else { return }
        // 隐藏所有视图,再显示选中的那个
        childViews.forEach { $0.isHidden = true }
        childViews[selectedIndex].isHidden = false
    }
}

注意要点

  • 确保TabBar的items数量和子视图/子控制器的数量完全匹配,避免索引越界问题。
  • 如果使用子控制器的方式,一定要正确调用addChild、didMove(toParent:)等生命周期方法,避免内存泄漏或视图生命周期异常。
  • MDCTabBar的样式你已经调整好了,这两种方案都不会影响你已有的界面效果,只需要关联视图逻辑就行。

内容的提问来源于stack exchange,提问作者Amirmahdi Mohammdi

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.20 08:57:47