Sheet và FullScreen trong SwiftUI
1. Sheet cơ bản
struct ContentView: View {
@State private var showSheet = false
var body: some View {
Button("Show Sheet") {
showSheet = true
}
.sheet(isPresented: $showSheet) {
SheetContent()
}
}
}
struct SheetContent: View {
@Environment(\.dismiss) var dismiss
var body: some View {
VStack {
Text("Sheet Content")
Button("Dismiss") {
dismiss()
}
}
}
}2. Full Screen Cover
struct ContentView: View {
@State private var showFullScreen = false
var body: some View {
Button("Show Full Screen") {
showFullScreen = true
}
.fullScreenCover(isPresented: $showFullScreen) {
FullScreenView()
}
}
}3. Sheet với Item
struct ContentView: View {
@State private var selectedProduct: Product?
var body: some View {
List(products) { product in
Button(product.name) {
selectedProduct = product
}
}
.sheet(item: $selectedProduct) { product in
ProductDetailSheet(product: product)
}
}
}4. Detents (Sheet Heights)
struct ContentView: View {
@State private var showSheet = false
var body: some View {
Button("Show Sheet") {
showSheet = true
}
.sheet(isPresented: $showSheet) {
SheetContent()
.presentationDetents([.medium, .large])
.presentationDragIndicator(.visible)
}
}
}
// Custom detent
.presentationDetents([
.height(200),
.fraction(0.5),
.medium,
.large
])5. Sheet Customization
SheetContent()
.presentationDetents([.medium, .large])
.presentationDragIndicator(.visible)
.presentationCornerRadius(20)
.presentationBackground(.ultraThinMaterial)
.interactiveDismissDisabled() // Không thể swipe dismiss6. Passing Data Back
Using Binding
struct ParentView: View {
@State private var showEditor = false
@State private var name = ""
var body: some View {
VStack {
Text("Name: \(name)")
Button("Edit") { showEditor = true }
}
.sheet(isPresented: $showEditor) {
NameEditor(name: $name)
}
}
}
struct NameEditor: View {
@Binding var name: String
@Environment(\.dismiss) var dismiss
var body: some View {
VStack {
TextField("Name", text: $name)
Button("Save") { dismiss() }
}
.padding()
}
}Using Callback
struct ParentView: View {
@State private var showPicker = false
@State private var selectedColor = Color.blue
var body: some View {
Circle()
.fill(selectedColor)
.onTapGesture { showPicker = true }
.sheet(isPresented: $showPicker) {
ColorPickerSheet { color in
selectedColor = color
}
}
}
}
struct ColorPickerSheet: View {
@Environment(\.dismiss) var dismiss
var onSelect: (Color) -> Void
let colors: [Color] = [.red, .blue, .green, .orange]
var body: some View {
VStack {
ForEach(colors, id: \.self) { color in
Button {
onSelect(color)
dismiss()
} label: {
Circle().fill(color).frame(width: 50, height: 50)
}
}
}
}
}7. Confirmation antes de dismiss
struct UnsavedChangesSheet: View {
@Environment(\.dismiss) var dismiss
@State private var hasChanges = false
@State private var showConfirmation = false
var body: some View {
VStack {
TextField("Content", text: .constant(""))
.onChange(of: text) { hasChanges = true }
Button("Save") { dismiss() }
}
.interactiveDismissDisabled(hasChanges)
.onDisappear {
if hasChanges {
showConfirmation = true
}
}
.confirmationDialog("Discard changes?", isPresented: $showConfirmation) {
Button("Discard", role: .destructive) { dismiss() }
Button("Cancel", role: .cancel) { }
}
}
}8. Multiple Sheets
struct ContentView: View {
@State private var activeSheet: SheetType?
enum SheetType: Identifiable {
case settings, profile, help
var id: Self { self }
}
var body: some View {
VStack {
Button("Settings") { activeSheet = .settings }
Button("Profile") { activeSheet = .profile }
Button("Help") { activeSheet = .help }
}
.sheet(item: $activeSheet) { sheet in
switch sheet {
case .settings: SettingsView()
case .profile: ProfileView()
case .help: HelpView()
}
}
}
}📝 Tóm tắt
| Modifier | Mục đích |
|---|---|
.sheet | Modal sheet |
.fullScreenCover | Full screen modal |
.presentationDetents | Sheet height |
@Environment(\.dismiss) | Dismiss action |
Last updated on