如何使用MDCTabBar?已开发应用但不知配置childView
嘿,我帮你梳理下MDCTabBar配置childView的两种常用方案,都是实际项目里验证过的,你可以根据自己的需求选:
方案一:搭配UIPageViewController实现滑动联动(推荐)
这种方式能让TabBar和页面滑动完美联动,体验更流畅,也是Material Design推荐的交互模式。步骤如下:
- 配置MDCTabBar并设置代理:先把TabBar的items配置好,然后设置它的代理来监听选中事件。
- 初始化UIPageViewController:把它作为子控制器加到你的容器视图中,负责管理所有子页面的切换。
- 关联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切换静态视图,这种方式更简单:
- 创建容器视图:用来承载所有子视图。
- 添加所有子视图到容器:初始状态下只显示第一个视图,其余隐藏。
- 监听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
相关产品推荐
相关产品推荐

