前语

每个 UI 规划师都喜爱美丽而有动画效果的 Tab Bar。然而,关于开发人员来说,完结这种规划可能是一场噩梦。当然,运用 Apple 的原生 Tab Bar 组件并专注于更有趣的工作,比如业务逻辑的完结,会更容易。但假如咱们有必要创立自界说 Tab Bar 该怎么完结呢?

Swift 怎么完结自界说 Tab Bar

介绍完结流程

在本文中,将测验答复这些问题。咱们将介绍创立自界说 Tab Bar 的最重要方面。终究效果将是一个具有动画效果、易于扩展、完全自界说的 Tab Bar,期望它能为你节约将来的时间,使规划师朝思暮想的 Tab Bar 的完结更方便和更舒适。下面来介绍一下完结流程:

首要,需求说明的是,本示例运用了一些依靠项。借助这些依靠项,更容易完结本文中描绘的解决方案。随时将它们替换为你的本机代码或其他库。这些依靠关系包含:

  • 用于布局的 SnapKit
  • 用于处理 Tab Bar 项上的点击操作的 RxGesture
  • 用于通知 TabBarController 选中项目的 RxSwift

现在,让咱们来完结这个功能。

Tab Bar 初步介绍

Tab Bar 项组件由两个不同的部分组成:视图层和处理所有界说的项目类型的枚举。

为什么运用枚举类型而不是简略的结构?

这很简略,枚举在编程中特别是在 Swift 语言中是强大的类型。它们将熟悉的状况汇总在一起,可迭代,可以扩展以打开有关特定状况的信息,或许可以在其中运用核算特点。

此外,枚举与结构相同是值类型。

enum CustomTabItem: String, CaseIterable {
    case profile
}
extension CustomTabItem {
    var viewController: UIViewController { }
    var icon: UIImage? { }
    var selectedIcon: UIImage? { }
    var name: String { }
}

根据上面的代码可以看出,CustomTabItem 具有用于图标、选定图标、称号和相关 viewController 的特点。每个值都运用 switch 语句界说,为每个枚举状况回来特定值。

第二部分是 Tab Bar 项的视图层。它直接与 CustomTabItem 相关,由于 Tab Bar 项是初始化期间传递给视图的两个参数之一。第二个参数是每个视图仅有的索引,稍后将用于更改 Tab Bar 的 selectedIndex

此外,每个视图都具有简略的过渡动画。项目的规划很简略,包含顶部的图标和下面的标题。根据项目是否已挑选,标题可以变成图标下面的圆线。

Tab Bar完结

让咱们聊聊怎么将所有 Tab Bar 项汇总并处理其挑选的首要组件。主动布局非常容易,由于它是 UIStackView 组件的子类。仅有需求做的工作便是运用 addArrangedSubview(_ view: UIView) 办法增加咱们的项目。这是在 setupHierarchy() 办法中处理的。

GitHub 存储库的 Extensions.swift 文件中,可以找到一些有用的扩展,比如用一行代码向 UIStackView 增加许多子视图的扩展。

此外,关于要增加到 Tab Bar 的每个项目,咱们有必要将 translatesAutoresizingMaskIntoConstraints 设置为 false,以避免主动创立它们的主动布局,并将 clipsToBounds 设置为 true,以将咱们的项目剪切到 Tab Bar 的鸿沟。咱们将在 setupProperties() 办法中完结这一部分,以及其他特点装备。

final class CustomTabBar: UIStackView {
    var itemTapped: Observable<Int> { itemTappedSubject.asObservable() }
    private let itemTappedSubject = PublishSubject<Int>()
    private let disposeBag = DisposeBag()
    init() { }
    required init(coder: NSCoder) {
        fatalError("init(coder:) has not been implemented")
    }
}

除了Tab Bar项的声明之外,咱们还有必要增加负责宣布所选项目索引的 Observable 序列特点。

正如上面所示,主体自身声明为私有常量,而且具有关于主题的值的 Observable。

由于这样做,咱们可以保证没有人可以干扰从 CustomTabBar 类外部宣布的该主题的值。

最后但相同重要的是,咱们有必要增加两个办法到咱们的 CustomTabBar 完结中。第一个是 selectItem(index: Int),在这里,咱们将处理更新当时所选项目的所有逻辑。

首要,咱们更新每个项目中的 isSelected 特点,以反映最新的挑选。

其次,咱们运用上面描绘的主题宣布所选项目的索引。经过这种办法,咱们同时在 TabBarController 和 Tab Bar 项中更新挑选。中心代码如下:

private func selectItem(index: Int) {
    customItemViews.forEach { $0.isSelected = $0.index == index }
    itemTappedSubject.onNext(index)
}

咱们有必要完结的第二个办法是 bind(),负责处理用户对咱们的每个项目的触摸。

完结运用 RxGesture,但假如你乐意,可以用你自己的 Reactive 扩展替换它。RxGesture 供给了一种 .tapGesture() 办法,用于辨认用户交互,但在绑定到该操作之前,咱们有必要过滤用户手势,仅挑选具有已辨认状况的手势。中心代码如下:

private func bind() {
    profileItem.rx.tapGesture()
        .when(.recognized)
        .bind { [weak self] _ in
            guard let self = self else { return }
            self.profileItem.animateClick {
                self.selectItem(index: self.profileItem.index)
            }
        }
        .disposed(by: disposeBag)
}

如上面代码,animateClick(completion: @escaping () -> Void) 的闭包内部调用了 selectItem(index: Int) 办法。这是一个 UIView 的扩展,用于缩放动画咱们的项目。

上面的代码示例介绍了怎么处理 profileItem 的用户交互。但不要忘掉以相同的办法处理其他相关的组件!

布局在 Tab Bar Controller 中

到目前为止,前期工作都已完结,现在咱们有必要将所有部分组合在一起!咱们可以运用 CustomTabBarController 来完结,但首要,咱们需求一个用于处理与 Tab Bar 项目相关的不同屏幕的简略视图控制器。代码如下:

class ViewController: UIViewController {
    private let titleLabel = UILabel()
    private let item: CustomTabItem
    init(item: CustomTabItem) {
        self.item = item
        super.init(nibName: nil, bundle: nil)
    }
    required init?(coder: NSCoder) {
        fatalError("init(coder:) has not been implemented")
    }
}

上面的示例成心省略了主动布局和特点装备,由于这是一个简略的增加。每个视图控制器都运用 CustomTabItem 进行初始化,因此咱们可以在屏幕上显示项目的称号。

回到 Tab Bar 控制器,除了层次结构和布局设置之外,咱们有必要装备一些特点。代码如下:

private func setupProperties() {
    tabBar.isHidden = true
    customTabBar.translatesAutoresizingMaskIntoConstraints = false
    customTabBar.addShadow()
    selectedIndex = 0
    let controllers = CustomTabItem.allCases.map { $0.viewController }
    setViewControllers(controllers, animated: true)
}

首要,躲藏可以经过名为 tabBar 的类特点访问的本机 Tab Bar。

其次,咱们将 translatesAutoresizingMaskIntoConstraints 设置为 false,并向自界说 TabBar 组件增加一些阴影。

最后,咱们有必要将 Tab Bar ControllerselectedIndex 特点设置为起始值(最常见的状况是将该值设置为 0),并设置将由 Tab Bar Controller 处理的视图控制器。

由于咱们的 Tab Bar Item 完结具有与每个枚举映射到其各自值的 View Controller 相相关的特点,而且它是 CaseIterable,因此咱们可以轻松地将咱们的枚举的所有状况映射到它们各自的 View Controller 值。映射后,它们将运用:

setViewControllers(_ controllers: [UIViewController], animated: true)

现在只剩下一步,咱们有必要处理当时 selectedIndex 的更改。

假如你在之前有所关注,那么你将立即知道怎么完结这一点。当然是经过 CustomTabBar 类中曾经创立的 Observable 序列,从而完结这个功能。

关于从 CustomTabBar 类外部宣布的每个索引值,咱们挑选特定的选项卡,经过 selectTabWith(index: Int) 办法将作为参数传递的索引分配给Tab Bar Controller 的 selectedIndex 特点。

自界说Tab Bar完结的终究成果

Swift 怎么完结自界说 Tab Bar

至此,咱们就完结了自界说Tab Bar的完结!

总结

总的来说,这篇文章详细介绍了怎么创立一个自界说的 Tab Bar,为移动使用的 UI 规划增添了美感和交互性。咱们从枚举类型的优势开端,解释了为什么运用枚举来界说 Tab Bar 的各个项目。经过对 Tab Bar 项的视图层的规划和动画效果,咱们使 Tab Bar 愈加生动和吸引人。

文章还深入评论了自界说 Tab Bar 的完结,包含处理用户交互、布局和在 Tab Bar Controller 中的装备。咱们运用了 RxSwift 等工具来处理项目挑选,并展示了怎么将所有这些部分组合在一起,以完结一个完全自界说的 Tab Bar。

终究,这个自界说 Tab Bar 为 UI 规划师和开发人员供给了一个更灵敏的挑选,使得移动使用的界面愈加吸引人。期望本文的内容关于那些期望提升用户体会的开发人员和规划师来说是有益的,可以帮助他们更好地完结他们的创意和规划理念。