NavigationBar、ToolBar、TabView、Group等

  • Container概述
  • TabView在tabbar中嵌入视图
  • TabView创立UIPageViewController
  • Group对视图分组
  • StatusBar的显现和躲藏<
  • DisclosureGroup躲藏和显现内容
  • 创立Toolbar并向其增加按钮
  • 自定义ToolbarButton
  • TabView或List-cell增加一个badge
  • GroupBox可视化的对视图进行分组
  • 躲藏Tabbar、navigationBar、toolbars
  • 自定义Navigationbar、tabbar、toolbars的布景色

概述

文章首要共享SwiftUI Modifier的学习过程,将运用事例的办法进行说明。内容浅显易懂,Container展示部分调试成果,不过测验代码是齐全的。假如想要运行成果,能够移步Github下载code -> github事例链接

1、Container概述

SwiftUI的设计源自于便捷、易用,能够依据需求将一个视图放置在另一个视图中。这在处理常用的首要容器视图时特别有用,比方导航操控器和tabBar操控器。能够把任何视图放到另一个容器视图中,SwiftUI会自动调整它的布局。

在这方面,SwiftUI自己的容器-NavigationStackTabViewGroup等–与用自己的视图组合制造的容器没有什么不同。

2、运用TabView在tabbar中嵌入视图

SwiftUI的TabView供给了一个等价于UITabBarController的控件,答应我们让用户运用屏幕底部的一个栏在几个活泼视图之间切换。在其基本形式中,应该为每个item供给一个图像和标题,假如期望以编程办法操控哪个item是active的,还能够增加一个标记。

2.1、基本款式

创立两个具有不同图像、表土和标签的视图。

struct FFTabViewEnbedViews: View {
    var body: some View {
        TabView(selection: $selectedView) {
            Text("First View")
                .padding()
                .tabItem {
                    Image(systemName: "1.circle")
                    Text("First")
                }
                .tag(1)
            Text("Second View")
                .padding()
                .tabItem {
                    Image(systemName: "2.circle")
                    Text("Second")
                }
                .tag(2)
        }
    }

2.2、经过Label创立tabItem

除了分指定文本和图像,还能够运用Label视图将它们组合在一起。

struct FFTabViewEnbedViews: View {
    var body: some View {
        TabView(selection: $selectedView) {
            Text("Third View")
                .padding()
                .tabItem {
                    Label("Third", systemImage: "3.circle")
                }
                .tag(3)
        }
    }

从iOS15开端,不用明确的运用SF Symbols图标的填充变化,由于体系会自动填充。假如增加label,则能够经过修正item视图的挑选以编程办法操控active的item。

2.3、经过tag切换Item

把每个item的content中增加一个Button来模拟点击,经过增加一些新的状况来盯梢哪个item是活泼的,然后将其附加到TabView的tag。

struct FFTabViewEnbedViews: View {
    @State var selectedView = 4
    var body: some View {
        TabView(selection: $selectedView) {
            Button("Show Five View") {
                selectedView = 5
            }
            .padding()
            .tabItem {
                Label("Third", systemImage: "4.circle")
            }
            .tag(4)
            Button("Show Four View") {
                selectedView = 4
            }
            .padding()
            .tabItem {
                Label("Third", systemImage: "5.circle")
            }
            .tag(5)
        }
    }

只要数据类型契合Hashable,item的label能够是任何类型。整数可能是最好的,可是假如要进行任何有意义的程序化导航,则应该保证将标记放在视图的中心方位,例如静态特点。这是能够在许多地方共享的办法,从而下降犯错的危险。

调试成果

SwiftUI基础篇Container
SwiftUI基础篇Container
SwiftUI基础篇Container

3、运用TabView创立UIPageViewController

SwiftUI的TabView能够当作为一个UIPageViewController,能够制造在多个屏幕间滑动的Content,底部的分页点显现具体方位。要激活页面的视图款式,将.tabViewStyle()修饰符附加到TabView,传入参数.page。

3.1、.tabViewStyle(.page)

分页点是白色和半透明的白色,假如视图布景为白色,则看不到分页点

struct FFTabViewScrollingPages: View {
    var body: some View {
        TabView {
            Text("First")
            Text("Second")
        }
        .tabViewStyle(.page)
    }
}

3.2、.indexViewStyle(.page(backgroundDisplayMode: .always))

为了解决这个问题,能够在tabViewStyle()设置额外的修饰符来要求SwiftUI放置布景

struct FFTabViewScrollingPages: View {
    var body: some View {
        TabView {
            Text("First")
            Text("Second")
        }
        .tabViewStyle(.page)
        .indexViewStyle(.page(backgroundDisplayMode: .always))
    }
}

3.3、.tabViewStyle(.page(indexDisplayMode: .never))

能够经过像.page办法增加一个额外的参数来操控分页点的显现,假如不想显现分页点,能够直接传入.never

struct FFTabViewScrollingPages: View {
    var body: some View {
        TabView {
            Text("First")
            Text("Second")
        }
        .tabViewStyle(.page(indexDisplayMode: .never))
    }
}

调试成果

SwiftUI基础篇Container
SwiftUI基础篇Container

4、运用Group对视图分组

假如需求几个视图作为一个整体–例如,一起转换,那么能够运用SwiftUI的Group视图,这一点特别重要,由于由于潜在技术原因,一次最多向父视图增加10个视图

struct FFGroupView: View {
    var body: some View {
        //包括10个Text的Stack,当增加了11个视图的时分就会报错(Extra argument in call)
        //得到的错误是对成员“buildBlock()”的模糊引证。
        VStack {
            Text("Line 1")
            Text("Line 2")
            Text("Line 3")
            Text("Line 4")
            Text("Line 5")
            Text("Line 6")
            Text("Line 7")
            Text("Line 8")
            Text("Line 9")
            Text("Line 0")
        }
        Divider()
        //这是由于SwiftUI的视图构建体系有各式各样的代码,能够增加1-10个视图,
        //但不能增加第11个视图,可是,能够运用Group
        VStack {
            Group {
                Text("Line 1")
                Text("Line 2")
                Text("Line 3")
                Text("Line 4")
                Text("Line 5")
                Text("Line 6")
            }
            Group {
                Text("Line 7")
                Text("Line 8")
                Text("Line 9")
                Text("Line 0")
                Text("Line 11")
            }
        }
        //这种情况下就奇妙的绕过了10个视图的约束,由于这个时分VStack只包括了两个Group
    }
}

调试成果

SwiftUI基础篇Container

5、StatusBar的显现和躲藏

运用SwiftUI的StatusBar()修饰符躲藏和显现iOS状况栏。接受一个躲藏参数,该参数有必要为true或false,取决于需求。

struct FFStatusbarHideAndShow: View {
    @State private var hideStatusBar = false
    var body: some View {
        //此修饰符仅在iOS上可用
        Text("No status bar, Please")
            .statusBar(hidden: false)
        //假如期望状况栏可见性依赖于某些程序状况,运用@state来代替hard-coded。
        //例如,创立一个hideStatusBar的bool值,当按钮被点击时,该bool值会被切换,
        //从而操控状况栏是否显现。
        Button("Toggle Status Bar") {
            withAnimation {
                hideStatusBar.toggle()
            }
        }
        .statusBar(hidden: hideStatusBar)
    }
}

此case由于是设置了两遍,Text与Button一起设定了statusBar,想要看到Button点击的动态作用,将Text的.statusBar(hidden: false)代码注释掉,有搅扰。

调试成果

SwiftUI基础篇Container
SwiftUI基础篇Container

6、运用DisclosureGroup躲藏和显现内容

SwiftUI有一个专用的DisclosureGroup视图,它显现一个发表指示器,并包括其中的内容。在最简略的形式中,他能够彻底由用户操控,但也能够将其绑定到一个bool特点,确认当前内容是否可见。

6.1、DisclosureGroup

创立一个包括很多文本的DisclosureGroup

struct FFDisclosureGroupHide: View {
    var body: some View {
        DisclosureGroup("Show Terms") {
            Text("噫吁嚱,危乎高哉!蜀道之难,难于上青天!蚕丛及鱼凫,开国何茫然!尔来四万八千岁,不与秦塞通人烟。西当太白有鸟道,能够横绝峨眉巅。地崩山摧壮士死,然后天梯石栈相钩连。上有六龙回日之高标,下有冲波逆折之回川。黄鹤之飞尚不得过,猿猱欲度愁攀援。青泥何盘盘,百步九折萦岩峦。扪参历井仰胁息,以手抚膺坐长叹。")
        }
        .frame(width: 300)
        .padding()
    }
}

6.2、经过修正bool值,操控是否展开Content

假如想要盯梢发表组是否翻开,能够将其绑定到bool值

struct FFDisclosureGroupHide: View {
    @State private var revealDetails = true
    var body: some View {
        DisclosureGroup("Show Terms", isExpanded: $revealDetails) {
            Text("噫吁嚱,危乎高哉!蜀道之难,难于上青天!蚕丛及鱼凫,开国何茫然!尔来四万八千岁,不与秦塞通人烟。西当太白有鸟道,能够横绝峨眉巅。地崩山摧壮士死,然后天梯石栈相钩连。上有六龙回日之高标,下有冲波逆折之回川。黄鹤之飞尚不得过,猿猱欲度愁攀援。青泥何盘盘,百步九折萦岩峦。扪参历井仰胁息,以手抚膺坐长叹。")
        }
        .frame(width: 300)
    }
}

调试成果

SwiftUI基础篇Container
SwiftUI基础篇Container

7、创立Toolbar并向其增加按钮

SwiftUI的toolbar()修饰符能够在顶部或底部任何地方办法按钮item,但只要视图嵌入到NavigationStack中时才能够。

7.1、ToolbarItem

假如你想把按钮放在屏幕底部的工具栏中,运用Toolbar(),然后创立一个Toolbar item,指定方位为.bottomBar

struct FFToolbarButtons: View {
    var body: some View {
        NavigationStack {
            Text("Hello, World!")
                .padding()
                .navigationTitle("SwiftUI")
                .toolbar(content: {
                    ToolbarItem(placement: .bottomBar) {
                        Button("Press Me") {
                            print("Toolbar Bottom")
                        }
                    }
                })
        } 
    }
}

7.2、ToolbarItemGroup

要创立多个Button,运用ToolbarItemGroup而不是ToolbarItem,设置多个Button

struct FFToolbarButtons: View {
    var body: some View {
        NavigationStack {
            Text("Hello, World!")
                .padding()
                .navigationTitle("SwiftUI")
                .toolbar(content: {
                    ToolbarItemGroup(placement: .bottomBar) {
                        Button("First") {
                            print("First")
                        }
                        Button("Second") {
                            print("Second")
                        }
                    }
                })
        }
    }
}

7.3、ToolbarItemGroup增加Spacer

假如想在ToolbarItemGroup中间增加距离,增加Spacer()即可

struct FFToolbarButtons: View {
    var body: some View {
        NavigationStack {
            Text("Hello, World!")
                .padding()
                .navigationTitle("SwiftUI")
                .toolbar(content: {
                    ToolbarItemGroup(placement: .bottomBar) {
                        Button("Third") {
                            print("T")
                        }
                        Spacer()
                        Button("Fouth") {
                            print("Fouth")
                        }
                    }
                })
        }
    }
}

调试成果

SwiftUI基础篇Container

8、自定义ToolbarButton

SwiftUI的工具栏答应用户自定义item,5个步骤:

  1. 为toolbar供给仅有的、稳定的标识符字符串。
  2. 为每个可自定义toolbar的item供给仅有的、稳定的标识符字符串。
  3. 在.secondaryaction类别中放置可定制的button
  4. 为toolbar启用编辑器模式,以便一切的辅佐操作都成为toolbar按钮
  5. “仅有、稳定”的标识符很重要,由于这是SwiftUI用来记住用户设置的–toolbar
struct FFToolbarCustomize: View {
    var body: some View {
        NavigationStack {
            Text("SwiftUI")
                .navigationTitle("Welcome")
                .toolbar(id: "options") {
                    ToolbarItem(id: "settings", placement: .primaryAction) {
                        Button("Settings") {
                            print("Settings")
                        }
                    }
                    ToolbarItem(id: "help", placement: .secondaryAction) {
                        Button("Help") {
                            print("Help")
                        }
                    }
                    ToolbarItem(id: "email", placement: .secondaryAction) {
                        Button("Email Me") {
                            print("Email me")
                        }
                    }
                    ToolbarItem(id: "credits", placement: .secondaryAction, showsByDefault: false) {
                        Button("Credits") {
                            print("Credits")
                        }
                    }
                    //默许情况下,这将使一切的非必须操作button都能够独自自定义,
                    //可是假如你在ControlGroup中包装两个或更多Button,
                    //则它们将被附加用于自定义目的--有必要一起增加或不增加
                    ToolbarItem(id: "font", placement: .secondaryAction) {
                        ControlGroup {
                            Button {
                                print("ControlGroup - 1")
                            } label: {
                                Label("Decrease font size", systemImage: "textformat.size.smaller")
                            }
                            Button {
                                print("ControlGroup - 2")
                            } label: {
                                Label("Increase font size", systemImage: "textformat.size.larger")
                            }
                        } label: {
                            Label("Font size", systemImage: "textformat.size")
                        }
                    }
                }
                .toolbarRole(.editor)
        }
        //假如没有为ControlGroup增加Label,SwiftUI将为他包括的按钮运用Label
    }
}

调试成果

SwiftUI基础篇Container
SwiftUI基础篇Container

9、TabView或List-cell增加一个badge

SwiftUI的Badge()修饰符能够向TabView item视图和list-cell增加数字和文本,目的将用户的注意力吸引到一些补偿状况信息上–例如,TabView上的数字标识未读消息。

struct FFTabViewBadge: View {
    var body: some View {
        TabView {
            VStack {
                List {
                    Text("Wi-Fi")
                        .badge("Lan solo")
                    Text("Bluetooth")
                        .badge("On")
                }
            }
            .tabItem {
                Label("Home", systemImage: "house")
            }
            .badge(5)
        }
    }
}

badge相同适用于List-cell,并自动以第二种色彩显现为右对齐文本。

调试成果

SwiftUI基础篇Container

10、GroupBox可视化的对视图进行分组

SwiftUI的GroupBox视图将视图组合在一起,并在他后面放置浅色布景,以便突出。假如需求的话,还能够挑选包括一个标题来制造组标题。

struct FFGroupBox: View {
    var body: some View {
        GroupBox {
            Text("Your account")
                .font(.headline)
            Text("Username: metabblv@163.com")
            Text("City: Shanghai")
        }
        //经过Stack修正对齐办法
        GroupBox {
            VStack(alignment:.leading) {
                Text("Your account")
                    .font(.headline)
                Text("Username: metabblv@163.com")
                Text("City: Shanghai")
            }
        }
        //GroupBox的真实强大的功用,假如嵌套它们,会自动调整色彩,以便明晰的区别。
        GroupBox {
            Text("Outer Content")
            GroupBox {
                Text("Middle Content")
                GroupBox {
                    Text("Inner Content")
                }
            }
        }
    }
}

调试成果

SwiftUI基础篇Container

11、怎么躲藏Tabbar、navigationBar、toolbars

SwiftUI的toolbar()修饰符答应我们在需求的时分躲藏或显现任何体系栏,当你有一个TabView想要在导航推送之后躲藏的时分,这个修饰符特别有用。将修饰符附加到能够触发躲藏或显现toolbar的任何视图上。

11.1、

struct FFBarsHidden: View {
    var body: some View {
        TabView {
            NavigationStack {
                NavigationLink("Tap Me") {
                    Text("Detail View")
                        .toolbar(.hidden, for: .tabBar)
                }
                .navigationTitle("Primary View")
            }
            .tabItem {
                Label("Home", systemImage: "house")
            }
        }
    }
}

假如没有指定要躲藏的是谁(for:tabbar),那么躲藏作用将流向最近的容器,可能是导航栏被躲藏。

11.2、动态躲藏NavigationBar

当随时改动传递给toolbar的值,就能够动态切换导航栏了

struct FFBarsDetailView: View {
    @State private var showNavigationBar = true
    var body: some View {
        Text("Detail View")
            .toolbar(showNavigationBar ? .visible : .hidden)
            .onTapGesture {
                withAnimation {
                    showNavigationBar.toggle()
                }
            }
    }
}
struct FFBarsHidden: View {
    var body: some View {
        TabView {
            NavigationStack {
                NavigationLink("DetailView", destination: FFBarsDetailView.init())
                    .navigationTitle("Primary View")
            }
            .tabItem {
                Label("Detail", systemImage: "1.circle")
            }
        }
    }
}

调试成果

SwiftUI基础篇Container
SwiftUI基础篇Container
SwiftUI基础篇Container

12、自定义Navigationbar、tabbar、toolbars的布景色

SwiftUI的toolbarBackground()修饰符能够自定义工具来在app中的外观,依据需求操控NavigationStack、TabView和其他toolbar款式。

12.1、设置Navigationbar布景色

显现包括100行的list,导航栏布景为蓝绿色

struct FFBarsBackground: View {
    var body: some View {
        TabView {
            NavigationStack {
                List(0..<100) {
                    Text("Row \($0)")
                }
                .navigationTitle("100 Rows")
                .toolbarBackground(.teal, for: .navigationBar)
            }
            .tabItem {
                Label("First", systemImage: "1.circle")
            }
        }
    }
}

在这里挑选的布景值在体系以为必要时运用,而不是总是可见的。因而,在上面的代码中,navigationbar开端是没有色彩的,翻滚后会改动。

12.2、Toolbar独自上色

假如期望为一个或两个栏类型上色,或许期望为每个栏供给不同的款式,则能够向toolbarBackground供给第二个参数以取得外的操控。

struct FFBarsBackground: View {
    var body: some View {
        //显现包括100行的list,导航栏布景为蓝绿色
        TabView {
            NavigationStack {
                List(0..<100) {
                    Text("Row \($0)")
                }
                .navigationTitle("100 Rows")
                .toolbarBackground(.orange, for: .navigationBar, .tabBar)
            }
            .tabItem {
                Label("Second", systemImage: "list.bullet")
            }
        }
    }

12.3、彻底躲藏

能够彻底躲藏布景,而不是指定布景色彩

struct FFBarsBackground: View {
    var body: some View {
        //显现包括100行的list,导航栏布景为蓝绿色
        TabView {
            NavigationStack {
                List(0..<100) {
                    Text("Row-Third \($0)")
                }
                .navigationTitle("100 Rows")
                .toolbarBackground(.hidden)
            }
            .tabItem {
                Label("Third", systemImage: "list.bullet")
            }
        }
    }

当翻滚时,列表内容直接出现在导航标题上。假如选用这种办法,请保证你的首要内容与toolbar重叠时不会发生UI问题。

调试成果

SwiftUI基础篇Container
SwiftUI基础篇Container
SwiftUI基础篇Container
SwiftUI基础篇Container
SwiftUI基础篇Container
SwiftUI基础篇Container