在SwiftUI中实现自定义的高度灵活的标签栏

在SwiftUI中实现自定义的高度灵活的标签栏

标签栏组件是UI界面中非常重要的组件,它通过创建一组清晰的选项卡按钮(标签),使得用户能够轻松地识别并切换到不同的内容区域,从而在一个界面上展现多个不同主题的丰富内容 。

SwiftUI提供了一个内置的标签栏组件,即TabView组件,但这个组件不够灵活,虽然通过定制可以解决一些问题,但很难适应一些更复杂的场景。

这篇博文介绍一种完全自定义的高度灵活的标签栏实现方式,可以作为SwiftUI 的标签栏组件的补充。

设计思路

通常标签栏组件可以分解为三部分: 标签部分(Tab),标签栏部分(TabBar),以及标签内容部分,即TabPage。我们的思路是,将这三部分独立设计,让它们独立发展,从而可以提供各种组合以实现高度灵活性。 标签部分需要数据支持,可以是数组,也可以是枚举,或者其他类型的数据, 我们用协议实现;标签栏的主要功能是对一组标签进行布局排列,我们用定制的组件实现;标签内容部分主要显示当前标签的内容,这个和具体业务需求相关,无需任何设计,直接在业务代码中实现,但需要遵循一定规范。 如下是我们的设计代码:

swift 复制代码
//标签协议
protocol HDXTab
{
    associatedtype TAB:View
    @ViewBuilder  
    func makeTab(isSelected:Bool,action:@escaping ()->Void)->TAB
}

//标签栏组件 
struct HDXTabBar<Content:View>:View
{
    var content: ()->Content  
    var body:some View 
    {
        self.content() 
    }
}

上面代码中,大家可能会觉得标签栏组件很奇怪,似乎和标签(Tab)没有任何关联,诀窍在于: 在标签栏的Content闭包中,我们可以直接引用标签的数据: 数组或者枚举。换句话说,这个关联是在闭包中完成的。

其实整个标签栏组件也是可以完全省略的,因为它的工作主要是对各标签进行排列布局,用SwiftUI提供各种内置布局组件就可以实现。之所以要设计标签栏组件,仅仅是需要通过一个组件名称以强化语义。

代码示例

下面按上述思路实现一个简单的普通的标签栏。效果如下图:。

我们用枚举为该组件建模。

枚举和标签栏组件有一种天然的联系,建议优先考虑用枚举为标签栏组件建模

swift 复制代码
//用枚举建模
enum  DemoTab:CaseIterable  
{
    case 首页  
    case 地址  
    case 收藏  
    case 我的  
    func getText()->String
    {
        return "\(self)"
    }
}

//对DemoTab进行扩展,使其遵循HDXTab协议:

extension DemoTab:HDXTab
{
     
    @ViewBuilder
    func makeTab(isSelected  : Bool, action: @escaping () -> Void) ->some View 
    {
        Button
        {
            action()
        } label:
        {
                 Text( self.getText())
                    .foregroundColor(isSelected ? .blue : .black)
         }
    }
}

下面是使用DemoTab组件的代码:

swift 复制代码
struct TabViewDemo:View 
{
    @State var selectedTab = DemoTab.首页 
    var body :some View
    {
        VStack
        { 
            ZStack
            {  
                //TabPage
                // Text(  selectedTab.getText()) 
                switch selectedTab {
                case .首页:  homeView()
                case .地址:  addressView()
                case .收藏:  favoriteView()  
                case .我的:  profileView()
                }
            }.frame(width:200,height:100)
            //TabBar
            HDXTabBar 
            {
                HStack { 
                 Spacer()
                    ForEach (DemoTab.allCases,id:\.self) { 
                       item  in   
                        //Tab
                        item.makeTab(isSelected:selectedTab == item) 
                        {
                            selectedTab = item   
                        }
                        Spacer()
                    }
                }
            }
           
        } 
    }
    
    @ViewBuilder
     func homeView()->some View
     {
       Text("this is home view")            
     }
      
    @ViewBuilder
    func addressView()->some View
    {
        Text("this is address view")            
    }
   
    @ViewBuilder
    func favoriteView()->some View
    {
        Text("this is favorite  view")            
    }
   
    @ViewBuilder
    func profileView()->some View
    {
        Text("this is profile view")            
    }
}

上述代码中,我们在标签栏组件中直接引用DemoTab枚举的各个枚举项,并调用其makeTab()方法构造标签,然后对标签进行布局。 另外,请特别注意标签切换的代码,以及展示标签内容(标签页)的代码,看起来似乎有些多,但由于使用了枚举建模,显得清晰和有条理。 HDXTabBar 这一层可以完全拿掉,如前所叙,仅仅是为了强调语义。

可以尝试对上面标签栏进行一些定制。比如,给每个标签加上图标,动画等等,将标签内容放置在标签栏之上,或者左面,或者右面,亦或者当标签比较多时,使用两行布局标签标签等等,这些需求在我们的实现中都非常容易实现。

小结

本文介绍了一种实现标签栏的方式,主要特点是让标签(Tab),标签栏(TabBar)以及标签内容(TabPage)独立变化,灵活组合,从而具有高度的灵活性。灵活性包括但不限于下面几个方面:

  • 定制的Tab风格

  • 定制的TabBar风格

  • 定制TabBar和TabPage之间的位置关系

相关推荐
struggle202515 小时前
Ollmao (OH-luh-毛程序包及源码) 是一款原生 SwiftUI 应用程序,它与 Ollama 集成,可在 Mac 上本地运行强大的 AI 模型
ios·swiftui·swift
货拉拉技术1 个月前
货拉拉用户端SwiftUI踩坑之旅
ios·swiftui·swift
ZacJi1 个月前
巧用 allowsHitTesting 自定义 SignInWithAppleButton
ios·swiftui·swift
刘争Stanley1 个月前
SwiftUI 是如何改变 iOS 开发游戏规则的?
ios·swiftui·swift
1024小神1 个月前
在swiftui中使用Alamofire发送请求获取github仓库里的txt文件内容并解析
ios·github·swiftui
大熊猫侯佩1 个月前
SwiftUI 撸码常见错误 2 例漫谈
swiftui·xcode·tag·tabview·preview·coredata·fetchrequest
东坡肘子2 个月前
肘子的 Swift 周报 #063|异种肾脏移植取得突破
swiftui·swift·apple
恋猫de小郭2 个月前
什么?Flutter 可能会被 SwiftUI/ArkUI 化?全新的 Flutter Roadmap
flutter·ios·swiftui
靴子学长2 个月前
iOS + watchOS Tourism App(含源码可简单复现)
mysql·ios·swiftui
hxx2212 个月前
iOS swift开发系列--如何给swiftui内容视图添加背景图片显示
ios·swiftui·swift