Swift开发:实现顶部3个切换标签(TableView、TextView),替代UITabBarController
嘿,完全懂你的困扰!你要的是顶部切换标签,而UITabBarController是底部导航的方案,确实和你想要的效果不匹配——别慌,给你两个靠谱的实现方案,都是专门针对顶部标签切换的:
方案一:UISegmentedControl + 容器视图(最直接简单)
这是实现顶部标签切换最基础的方式,逻辑清晰,代码量也不大,步骤如下:
先准备三个子视图控制器:
- 第一个是带你需要的TableView的
FirstTableVC - 第二个是带另一款TableView的
SecondTableVC - 第三个是承载TextView的
TextDisplayVC
- 第一个是带你需要的TableView的
在主视图控制器(比如叫
MainVC)的顶部添加UISegmentedControl,设置好三个标签的标题。在
MainVC里加一个容器视图(Container View),用来承载上面三个子VC的内容。实现切换逻辑,点击分段控件时替换容器里的子VC:
class MainVC: UIViewController { // 从Storyboard拖线连接容器视图 @IBOutlet weak var containerView: UIView! // 从Storyboard拖线连接顶部分段控件 @IBOutlet weak var topSegmentControl: UISegmentedControl! // 存储三个子控制器的数组 private var childVCs: [UIViewController] = [] override func viewDidLoad() { super.viewDidLoad() // 初始化三个子VC let firstTableVC = FirstTableVC() let secondTableVC = SecondTableVC() let textVC = TextDisplayVC() childVCs = [firstTableVC, secondTableVC, textVC] // 默认显示第一个标签对应的VC switchToVC(at: 0) // 给分段控件添加点击事件 topSegmentControl.addTarget(self, action: #selector(segmentTapped(_:)), for: .valueChanged) } @objc private func segmentTapped(_ sender: UISegmentedControl) { switchToVC(at: sender.selectedSegmentIndex) } private func switchToVC(at index: Int) { // 先移除容器里现有的子视图和子VC containerView.subviews.forEach { $0.removeFromSuperview() } childVCs.forEach { $0.removeFromParent() } // 获取目标子VC let targetVC = childVCs[index] // 将目标VC添加到容器中 addChild(targetVC) targetVC.view.frame = containerView.bounds containerView.addSubview(targetVC.view) targetVC.didMove(toParent: self) } }
方案二:UIPageViewController + 分段控件(支持滑动切换)
如果想要更流畅的用户体验(比如支持左右滑动切换标签),可以用UIPageViewController配合顶部的分段控件,实现起来也不难:
class MainVC: UIPageViewController, UIPageViewControllerDataSource, UIPageViewControllerDelegate { // 自定义顶部分段控件 private let topSegment = UISegmentedControl(items: ["标签1", "标签2", "标签3"]) // 存储三个子控制器的数组 private let childVCs: [UIViewController] = [FirstTableVC(), SecondTableVC(), TextDisplayVC()] override func viewDidLoad() { super.viewDidLoad() // 设置数据源和代理 dataSource = self delegate = self // 配置分段控件 topSegment.selectedSegmentIndex = 0 topSegment.addTarget(self, action: #selector(segmentTapped(_:)), for: .valueChanged) topSegment.translatesAutoresizingMaskIntoConstraints = false view.addSubview(topSegment) // 给分段控件加约束,固定在顶部安全区 NSLayoutConstraint.activate([ topSegment.topAnchor.constraint(equalTo: view.safeAreaLayoutGuide.topAnchor), topSegment.leadingAnchor.constraint(equalTo: view.leadingAnchor), topSegment.trailingAnchor.constraint(equalTo: view.trailingAnchor), topSegment.heightAnchor.constraint(equalToConstant: 44) ]) // 默认显示第一个标签对应的VC setViewControllers([childVCs[0]], direction: .forward, animated: false) } @objc private func segmentTapped(_ sender: UISegmentedControl) { let selectedIndex = sender.selectedSegmentIndex // 根据切换方向设置动画 let direction: UIPageViewController.NavigationDirection = selectedIndex > (childVCs.firstIndex(of: viewControllers?.first ?? childVCs[0]) ?? 0) ? .forward : .reverse setViewControllers([childVCs[selectedIndex]], direction: direction, animated: true) } // UIPageViewControllerDataSource:返回上一个VC func pageViewController(_ pageViewController: UIPageViewController, viewControllerBefore viewController: UIViewController) -> UIViewController? { guard let index = childVCs.firstIndex(of: viewController), index > 0 else { return nil } return childVCs[index - 1] } // UIPageViewControllerDataSource:返回下一个VC 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] } // 滑动切换完成后,同步更新分段控件的选中状态 func pageViewController(_ pageViewController: UIPageViewController, didFinishAnimating finished: Bool, previousViewControllers: [UIViewController], transitionCompleted completed: Bool) { guard completed, let currentVC = pageViewController.viewControllers?.first, let index = childVCs.firstIndex(of: currentVC) else { return } topSegment.selectedSegmentIndex = index } }
方案对比
- 方案一:实现简单,适合不需要滑动切换的场景,代码维护成本低。
- 方案二:支持手势滑动切换,用户体验更好,适合需要更流畅交互的场景。
完全不用纠结UITabBarController,它就是为底部导航设计的,上面两种方案才是你要的顶部标签切换的正确打开方式~
内容的提问来源于stack exchange,提问作者user979331
相关产品推荐
相关产品推荐

