SwiftUI系列之七--NavigationView, TabbedView, Group介绍

SwiftUI系列之七--NavigationView, TabbedView, Group介绍_第1张图片
SwiftUI的设计就是开箱即用,这就意味着我们可以根据需要,将任意View放置到另一个View中。这一点对于我们常常使用的一些Container View是非常有用的,比如导航栏和底部tab栏。我们可以把任何一个View扔进Container中,SwiftUI会自动适应View的布局。本篇主要介绍这几种Container View:
NavigationView, TabbedView, Group

NavigationView

在前面的文章中其实已经见过几次NavigationView了,它对应UIKit中的UINavigationController。如果想拥有导航到别的控制器的能力,页面必须包裹进NavigationView中:

NavigationView{
   Text("Hello world")
}

1.设置导航栏title

上面创建的导航栏顶部是空的,我们可以为其添加一个title:

NavigationView{
   Text("Hello World!").navigationBarTitle("TEST")
}

系统默认给我们添加的是更摩登的title类型–居左的大标题,并且当页面向上滚动时标题会自动运动到导航栏正中位置,体验挺好,大家可以试试:
SwiftUI系列之七--NavigationView, TabbedView, Group介绍_第2张图片
但如果这不是你要的亚子,我们也可以设置成熟悉的导航栏样式:

NavigationView{
    Text("Hello World!").navigationBarTitle("TEST",displayMode: .inline)
}

SwiftUI系列之七--NavigationView, TabbedView, Group介绍_第3张图片
displayModeTitleDisplayMode枚举的值,它有三种值:

  • automatic:从前一个导航栏继承显示模式
  • inline:展示标准导航条的title样式
  • large:即系统默认的样式,居左大标题

针对设置导航栏的title,我做了一个小实验:

NavigationView{
    List(streets){ street in
        NavigationLink(destination:ListViewDetial()){
             HStack(alignment:.center){
                  // TaskRow是自定义View
                  TaskRow().navigationBarTitle("Streets4", displayMode: .large)
                  TaskRow()
             }.navigationBarTitle("Streets3", displayMode: .large)
        }.navigationBarTitle("Streets2", displayMode: .large)
     }.navigationBarTitle("Streets1", displayMode: .inline)
}.navigationBarTitle("Streets", displayMode: .inline)

因为navigationBarTitle是View中的函数,所有遵守View协议的都可以调用navigationBarTitle修饰,但是我发现:

  • NavigationView调用navigationBarTitle设置title无效
  • Streets1Streets2同时设置的时候显示Streets2,表明内层的View会覆盖外层的设置;可是Streets2Streets3同时设置还是显示Streets2Streets3Streets4同时设置显示的Streets3,这好像又表明外层的设置优先级比较高,好吧,我懵逼了。。。后续再研究为什么吧,也许本身就没有规律,只要设置其中一个就生效了。

但我还是有个疑问,为什么这种针对导航栏的设置,不是直接NavigationView自身调用呢?好吧,知识浅薄的我,也许还没有意识到这其中的玄机呢。

2.导航栏左右添加按钮
想要给导航栏添加左右的按钮,只需要添加navigationBarItems()修饰,直接看代码:

	NavigationView{
    	Text("Hello World!")
    }
    .navigationBarTitle("TEST",displayMode: .inline)
    .navigationBarItems(leading: Button("Left"){
         print("leading button clicked!")
    }, trailing: Button("Right"){
         print("trailing button clicked!")
    }

SwiftUI系列之七--NavigationView, TabbedView, Group介绍_第4张图片
通常来说需要设置左右item为按钮,但是这完全没有限制,你可以设置任何View哦,而且可以设置多个,包裹在HStack中即可。

3.页面跳转和传值
在上面的小实验中其实已经用到了页面跳转,那如果我需要给详情页传值该怎么办呢?

NavigationView{
     List(streets){ street in
         NavigationLink(destination:ListViewDetial(someNeed:"someNeed"))
             HStack(alignment:.center){
                 TaskRow().navigationBarTitle("Streets4", displayMode: .large)
                 TaskRow()
             }.navigationBarTitle("Streets3", displayMode: .large)
          }
      }
}

假如有些值我需要从当前页面传到目的页面,只需要为目的页面增加属性,并实现相应的构造方法,在目的页就可以拿到从当前页传递的数据,是不是so easy?

TabView

TabView和UIKit中的UITabBarController一脉相承,可以在屏幕底部添加一个可以切换不同View的视图。

创建TabView时我们需要为每一项提供图片和标题,这和使用UITabBarController并无二致,不同的是TabView的tag,如果需要在代码中动态设置当前可见的tab,就需要设置。

TabView{
    Text("customView1").tabItem{
         Image(systemName: "1.circle")
         Text("item1")
    }.tag(0)
    Text("customView2").tabItem{
          Image(systemName: "2.circle")
          Text("item2")
    }.tag(1)
}

如果添加了tag,我们就可以动态控制显示哪个tab的页面了:

@State var selectedView = 1
TabView(selection: $selectedView) {
  ...
}

如下显示tab
SwiftUI系列之七--NavigationView, TabbedView, Group介绍_第5张图片

Group

在SwiftUI中,之前也提到过,一个View中不同存在超过十个子View,这是由SwiftUI的底层逻辑决定的,我们无能为力,那如果确实有超过十个的子view,应该怎么办?Group就是用来解决这个问题的。

现在假如有一个VStack中有10个Text:

VStack {
    Text("Line")
    Text("Line")
    Text("Line")
    Text("Line")
    Text("Line")
    Text("Line")
    Text("Line")
    Text("Line")
    Text("Line")
    Text("Line")
}

这时一切都OK的,但是一旦你再往里面加一个Text,就会里面出错

ambiguous reference to member 'buildBlock()

后面可能还会跟一系列的错误:

SwiftUI.ViewBuilder:3:24: note: found this candidate
    public static func buildBlock<C0, C1, C2, C3, C4, C5, C6, C7, C8, C9>(_ c0: C0, _ c1: C1, _ c2: C2, _ c3: C3, _ c4: C4, _ c5: C5, _ c6: C6, _ c7: C7, _ c8: C8, _ c9: C9) -> TupleView<(C0, C1, C2, C3, C4, C5, C6, C7, C8, C9)> where C0 : View, C1 : View, C2 : View, C3 : View, C4 : View, C5 : View, C6 : View, C7 : View, C8 : View, C9 : View

幸运的是我们有Group可以解决,像这样:

var body: some View {
    VStack {
        Group {
            Text("Line")
            Text("Line")
            Text("Line")
            Text("Line")
            Text("Line")
            Text("Line")
        }

        Group {
            Text("Line")
            Text("Line")
            Text("Line")
            Text("Line")
            Text("Line")
        }
    }
}

添加了Group的页面效果和之前完全一样,它的最大作用就是避免子view过多而报错,有时候用它来对一个页面的若干子view分组也是比较常见的操作。

好了,本篇主要介绍了NavigationView, TabbedView,Group这几种Container,你都学会了吗?每天进步一点点,成为更好的自己!欢迎关注微信公众号:iOS进化论,一起探索SwiftUI的世界!
SwiftUI系列之七--NavigationView, TabbedView, Group介绍_第6张图片
关注公众号iOS进化论,回复“干货”,就会得到很多干货资源哦,笔芯。
SwiftUI系列之七--NavigationView, TabbedView, Group介绍_第7张图片

你可能感兴趣的:(swift)