Sheet
- 运用Sheet-Present一个新视图
- 运用Sheets多重present
- Sheet的视图怎么dismiss
- 显现Popover视图
- 避免Sheet被dismiss
- 显现一个bottom-sheet
- 怎么展现白画面的占位图
概述
文章首要共享SwiftUI Modifier的学习过程,将运用事例的办法进行说明。内容深入浅出,Sheet展现部分调试成果,不过测试代码是齐全的。假如想要运行成果,能够移步Github下载code -> github事例链接
1、运用Sheet-Present一个新视图
SwiftUI的Sheets
用于视图上present
新视图,一起仍然答应用户在准备好时向下拖动以封闭新视图。要运用sheet,给他一些东西来显现(文本、图片、自界说View等),添加一个Bool值来界说DetailView是否应该被显现,然后将其作为模态sheet
附加到主视图上。
//例如,创立一个简单的DetailView,然后在点击Button时从ContentView-present它
struct SheetView: View {
@Environment(\.dismiss) var dismiss
var body: some View {
Button("Press to dismiss") {
dismiss()
}
.font(.title)
.padding()
.background(.black)
}
}
struct FFPresentSheets: View {
@State private var showingSheet = false
var body: some View {
Button("Show Sheet") {
showingSheet.toggle()
}
.sheet(isPresented: $showingSheet) {
SheetView()
}
}
}
假如在iOS14以下,运用@environment(.presentationMode) var presentationMode 和presentationMode.wrappedValue.dismiss()来替代。与导航push不同,Sheet不需求NavigationStack。 在iOS上,假如想封闭向下拖动封闭的操作,运用fullScreenCover()
润饰符。
2、运用Sheets多重present
假如想在SwiftUI中显现多个View页面,通过从第一个View-present第二个视图来完成,不能够将两个sheet()润饰符一起附加到一个父视图上。
struct FFPresentSheetsMultiple: View {
@State private var showingFirst = false
@State private var showingSecond = false
var body: some View {
VStack {
Button("Show First Sheet") {
showingFirst = true
}
}
.sheet(isPresented: $showingFirst) {
Button("Show Second Sheet") {
showingSecond = true
}
.sheet(isPresented: $showingSecond) {
Text("Second Sheet")
}
}
}
}
运用这种办法,两个Sheet都将正确显现。假如把两个Sheet()润饰符放在同一个父元素中,SwiftUI会失效,只显现第一个sheet。
调试成果
3、Sheet的视图怎么dismiss
当运用Sheet显现了一个SwiftUI视图时,通常想要在某些工作完成后封闭那个视图。例如当用户点击一个按钮时。在SwiftUI中有两种处理这个问题的办法。
3.1、@Environment(.dismiss)
第一个办法是告诉视图运用它自己的Presentation mode的环境变量来封闭。任何视图都能够封闭自己,不管它是怎么present的。运用@Environment(\.dismiss)
。
struct DismissingView_015_01: View {
@Environment(\.dismiss) var dismiss
var body: some View {
Button("Dismiss me") {
dismiss()
}
}
}
struct FFSheetViewDismiss: View {
@State private var showingDetail = false
@State private var showingDetail2 = false
var body: some View {
Button("Show Detail") {
showingDetail = true
}
.sheet(isPresented: $showingDetail) {
DismissingView_015_01()
}
}
}
3.2、@Binding state
别的一种挑选是将绑定
传递到所显现的Detail视图中,这样就能够将绑定值更改回false。仍然需求在sheet视图中拥有某种state属性,但现在它作为绑定传递给Detail视图。运用这种办法,视图将其绑定设置为false也会更新原始视图中的状况,导致Detail视图Dismiss
struct DismissingView_015_02: View {
@Binding var isPresented: Bool
var body: some View {
Button("Dismiss me") {
isPresented = false
}
}
}
struct FFSheetViewDismiss: View {
@State private var showingDetail = false
@State private var showingDetail2 = false
var body: some View {
Button("Show Detail2") {
showingDetail2 = true
}
.sheet(isPresented: $showingDetail2) {
DismissingView_015_02(isPresented: $showingDetail2)
}
}
}
3、fullScreenCover-present全屏视图
当想要全屏的时候,SwiftUI的fullScreenCover()
润饰符供给了一样显现办法,在代码中,他的工作原理简直与Sheet一样。常规的sheet能够通过向下拖动来封闭,但是运用fullScreenCover-present的视图是不能的,因此,供给一种办法来dismiss新视图是要处理的问题。fullScreenCover()在macOS上不可用。
struct FullScreenModalView_015: View {
@Environment(\.dismiss) var dismiss
var body: some View {
ZStack {
Color.primary.ignoresSafeArea(edges: .all)
Button("Dismiss modal") {
dismiss()
}
}
}
}
struct FFSheetFullScreenCover: View {
@State private var isPresented = false
var body: some View {
Button("Present!") {
isPresented.toggle()
}
.fullScreenCover(isPresented: $isPresented, content: FullScreenModalView_015.init)
}
}
4、显现Popover视图
SwiftUI有一个专门的润饰器来显现弹出窗口,在iPad上显现为漂浮的气泡,在iOS上是滑动。要显现弹出窗口,需求一些状况来确定弹出窗口是否可见。与alert不同,弹出窗口能够包含任何类型的视图,所以,只要把需求的东西放在弹出窗口中就能够。
struct FFSheetPopover: View {
@State private var showingPopover = false
var body: some View {
Button("Show Menu") {
showingPopover = true
}
.popover(isPresented: $showingPopover) {
Text("Your content here")
.font(.headline)
.padding()
}
}
}
5、避免Sheet被dismiss
SwiftUI供给了interactiveDismissDisabled()
润饰符来操控用户是否能够向下滑动来封闭一个Sheet View。例如,假如用户必须接受的协议,只用同意才干封闭。
5.1、interactiveDismissDisabled()
最简单的办法是,interactiveDismissDisabled()润饰符附加到你的Sheet Content上。
struct ExampleSheet_015_01: View {
@Environment(\.dismiss) var dismiss
var body: some View {
VStack {
Text("Sheet View")
Button("Dismiss", action: close)
}
.interactiveDismissDisabled()
}
func close() {
dismiss()
}
}
struct FFSheetSwipe: View {
@State private var showingSheet = false
@State private var showingSheet1 = false
var body: some View {
Button("Show Sheet") {
showingSheet.toggle()
}
.sheet(isPresented: $showingSheet, content: ExampleSheet_015_01.init)
}
}
5.2、设定dismiss的条件
能够将一个bool值绑定到润饰符,以答应swipe
仅在成功满意某些条件时才撤销。
struct ExampleSheet_015_02: View {
@State private var termsAccepted = false
var body: some View {
VStack {
Text("Terms and conditions")
.font(.title)
Text("Lots of legalese here")
Toggle("Accept", isOn: $termsAccepted)
}
.padding()
.interactiveDismissDisabled(!termsAccepted)
}
}
struct FFSheetSwipe: View {
@State private var showingSheet1 = false
var body: some View {
Button("Show Sheet 1") {
showingSheet1.toggle()
}
.sheet(isPresented: $showingSheet1, content: ExampleSheet_015_02.init)
}
}
6、显现一个bottom-sheet
SwiftUI的presentationsDetents()
润饰符能够创立从视图底部向上滑动的Sheet,能够不占满全屏,至于多少,依据需求来操控。
6.1、presentationDetents([.medium, .large])
一起支撑.medium和.large,SwiftUI将创立一个调整巨细的句柄,让用户在这两个size之间调整表单
struct FFSheetShowBottom: View {
@State private var showingCredits = false
var body: some View {
Button("Show Credits") {
showingCredits.toggle()
}
.sheet(isPresented: $showingCredits) {
Text("一起支撑.medium和.large")
.presentationDetents([.medium, .large])
}
}
}
6.2、presentationDragIndicator(.hidden)
躲藏提示条
struct FFSheetShowBottom: View {
@State private var showingCredits2 = false
var body: some View {
Button("Show Credits 2") {
showingCredits2.toggle()
}
.sheet(isPresented: $showingCredits2) {
Text("躲藏提示条")
.presentationDetents([.medium, .large])
.presentationDragIndicator(.hidden)
}
}
}
6.3、presentationDragIndicator(.hidden)
即使有自界说的显现控件,当有一个高度比较小的class时,sheet也会主动占有整个屏幕。比方,横向的iPhone。假如想支撑此场景,请确保供给一种办法来封闭sheet view。即使指定一个内置巨细外,还能够供给一个规模为0-1的自界说分数。例如,创立一个占用屏幕底部15%的sheet View
struct FFSheetShowBottom: View {
@State private var showingCredits3 = false
var body: some View {
Button("Show Credits 3") {
showingCredits3.toggle()
}
.sheet(isPresented: $showingCredits3) {
Text("创立百分比的占用高度")
.presentationDetents([.fraction(0.15)])
}
}
}
6.4、presentationDetents([.height(300)])
创立一个准确的高度
struct FFSheetShowBottom: View {
@State private var showingCredits4 = false
var body: some View {
Button("Show Credits 4") {
showingCredits4.toggle()
}
.sheet(isPresented: $showingCredits4) {
Text("固定高度")
.presentationDetents([.height(300)])
}
}
}
6.5、动态切换高度
能够依据需求给视图附加恣意多的detens,只要把他们悉数添加到detens的调集中,SwiftUI会主动处理。例如,能够让用户在从10%切换到100%
struct FFSheetShowBottom: View {
@State private var showingCredits5 = false
let heights = stride(from: 0.1, to: 1.0, by: 0.1).map { PresentationDetent.fraction($0) }
var body: some View {
Button("Show Credits 5") {
showingCredits5.toggle()
}
.sheet(isPresented: $showingCredits5) {
Text("动态切换高度")
.presentationDetents(Set(heights))
}
}
}
调试成果
7、怎么展现白画面的占位图
SwiftUI有一个专用的ContentUnavailableView
视图,在没有数据的时候向用户展现非空画面。例如,在用户执行了查找操作之后,并未查找到内容,运用此View。
7.1、基础款式
默认供给一个放大镜图标,由标题和副标题构成,用来展现用户并未查找到具体内容
struct FFContentUnavailable: View {
var body: some View {
ContentUnavailableView.search
}
}
7.2、自界说文本
假如有需求,能够对其进行自界说文本,以添加用户查找的内容
struct FFContentUnavailableCustom: View {
var body: some View {
ContentUnavailableView.search(text: "Life, the Universe, and Everything")
}
}
7.3、彻底自界说
彻底自界说所有的内容
struct FFContentUnavailableCustomAll: View {
var body: some View {
ContentUnavailableView("No favorites", systemImage: "star", description: Text("You don't have any favorites yet."))
.symbolVariant(.slash)
}
}