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自己的容器-NavigationStack
、TabView
、Group
等–与用自己的视图组合制造的容器没有什么不同。
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能够是任何类型。整数可能是最好的,可是假如要进行任何有意义的程序化导航,则应该保证将标记放在视图的中心方位,例如静态特点。这是能够在许多地方共享的办法,从而下降犯错的危险。
调试成果
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))
}
}
调试成果
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
}
}
调试成果
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)
代码注释掉,有搅扰。
调试成果
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)
}
}
调试成果
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")
}
}
})
}
}
}
调试成果
8、自定义ToolbarButton
SwiftUI的工具栏答应用户自定义item,5个步骤:
- 为toolbar供给仅有的、稳定的标识符字符串。
- 为每个可自定义toolbar的item供给仅有的、稳定的标识符字符串。
- 在.secondaryaction类别中放置可定制的button
- 为toolbar启用编辑器模式,以便一切的辅佐操作都成为toolbar按钮
- “仅有、稳定”的标识符很重要,由于这是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
}
}
调试成果
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,并自动以第二种色彩显现为右对齐文本。
调试成果
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")
}
}
}
}
}
调试成果
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")
}
}
}
}
调试成果
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问题。