SwiftUI - 可变高度的Sheet

公众号:RobotPBQ

在苹果升级到iOS16后,给sheet带来了非常好用的一个功能 presentationDetents高度可以自由控制,在iOS16之前高度是固定的,但是在iOS16以后你可以用sheet创造很多app中流行的效果。

presentationDetents 介绍

在 SwiftUI 中,sheet 修饰符的 presentationDetents 参数用于控制 sheet 被拖拽时的停靠位置。

presentationDetents 可以设置以下值:

  • .fraction(0.0) - 禁止停靠,可全范围拖拽
  • .fraction(0.5) - 中间停靠点
  • .fraction(1.0) - 最大停靠点
  • .medium - 预设中等停靠点
  • .large - 预设大停靠点

例子:

SwiftUI 复制代码
.sheet(isPresented: $showSheet) {
   // sheet内容 
}
.presentationDetents([.fraction(0.5)])

这将允许sheet被拖拽,并在屏幕垂直中心点停靠。

通过配置presentationDetents,可以控制sheet的拖拽和停靠交互,实现更丰富的用户体验。一般结合.interactive()使用。

他有两种初始化方法

SwiftUI 复制代码
方法一
public func presentationDetents(_ detents: Set<PresentationDetent>) -> some View

方法二
public func presentationDetents(_ detents: Set<PresentationDetent>, selection: Binding<PresentationDetent>) -> some View

第一个参数是一个Set集合, 内部类型是PresentationDetent. 内部提供了四种简便的方法来让你方便的控制高度

SwiftUI 复制代码
public struct PresentationDetent : Hashable {
    public static let medium: PresentationDetent // 高度大约是屏幕的一半
    public static let large: PresentationDetent // 和Sheet的高度相同
    public static func fraction(_ fraction: CGFloat) -> PresentationDetent // 屏幕的小数点比例,例如:0.5,就是屏幕的一半高度
    public static func height(_ height: CGFloat) -> PresentationDetent // 单位是PX,设置200,那么高度就是200

有了以上基本认识,我们来具体看看示例

先给出一个原来使用 sheet 的方法

SwiftUI 复制代码
struct ResizableSheetSample: View {
    @State var showSheet: Bool = false
    var body: some View {
        Button {
            showSheet.toggle()
        } label: {
            Text("Click me")
        }
        .sheet(isPresented: $showSheet) {
            MyCustomeView()
        }
    }
}

struct MyCustomeView: View {
    var body: some View {
        ZStack {
            Color.mint.ignoresSafeArea()
        }
    }
}

效果就是点击按钮,会弹出一个青色背景色的页面

presentationDetents 使用

大视图

这个效果和之前默认的效果是一样的

SwiftUI 复制代码
MyCustomeView()
.presentationDetents([.large])

中等试图

弹出的页面只有页面的一半高度

SwiftUI 复制代码
MyCustomeView()
.presentationDetents([.medium])

指定高度

弹出页面的高度为指定高度,单位为:PX

SwiftUI 复制代码
MyCustomeView()
.presentationDetents([.height(100)])

指定比例

弹出页面占整个页面的比例,范围为:0 ~ 1

SwiftUI 复制代码
MyCustomeView()
.presentationDetents([.fraction(0.6)])

是否隐藏指示器

可以隐藏或显示指示器,就是图片中绿色背景顶部的小黑杠

SwiftUI 复制代码
.presentationDragIndicator(.visible)

interactiveDismissDisabled 参数使用

使用此参数,弹出的sheet页面将无法收回。

SwiftUI 复制代码
.interactiveDismissDisabled()

实现不同位置的悬停

presentationDetents 可以设置多个值,实现不同位置的悬停效果

SwiftUI 复制代码
.presentationDetents([.fraction(0.3), .large, .medium, .height(130)])

在子页面改变页面的高度

要实现在子页面来改变页面的高度,我们就需要使用另一个方法来实现,它多了一个参数

SwiftUI 复制代码
public func presentationDetents(_ detents: Set<PresentationDetent>, selection: Binding<PresentationDetent>) -> some View
如何使用

我们需要在父视图传递一个参数到子视图

SwiftUI 复制代码
// 父视图
MyCustomeView(detentState: $detentState)
    .presentationDetents(
    [.fraction(0.3), .large, .medium, .height(600)],
    selection: $detentState
    )
    
// 子视图
struct MyCustomeView: View {
    @Binding var detentState: PresentationDetent
    var body: some View {
        ZStack {
            Color.mint.ignoresSafeArea()
            VStack(spacing: 30) {
                Button("large") {
                    detentState = .large
                }

                Button("medium") {
                    detentState = .medium
                }

                Button("height") {
                    detentState = .height(600)
                }

                Button("fraction") {
                    detentState = .fraction(0.3)
                }
            }
            .foregroundColor(.black)
        }
    }
}

我们在子视图中去改变这个值,就可以达到改变页面高度的效果

大家有什么看法呢?欢迎留言讨论。

相关推荐
大熊猫侯佩7 小时前
黑衣人档案:用 Apple Foundation Models + SwiftUI 打造 AI 聊天机器人全攻略
ios·swiftui·ai编程
大熊猫侯佩7 小时前
侠客行・iOS 26 Liquid Glass TabBar 破阵记
ios·swiftui·swift
qixingchao1 天前
iOS SwiftUI 动画开发指南
ios·swiftui·swift
大熊猫侯佩1 天前
猿族代码战记:Mutex 升级版——守护 Swift 并发的“香蕉仓库”
swiftui·swift·apple
大熊猫侯佩1 天前
寥寥几行代码实现 SwiftUI 超丝滑弹窗转场动画
ios·swiftui·swift
请叫我飞哥@2 天前
获取 Apple 授权登录的 Token
ios·swiftui·swift
我唔知啊4 天前
SwiftUI 支持呼吸动画的图片切换小控件
swiftui
东坡肘子6 天前
惊险但幸运,两次!| 肘子的 Swift 周报 #0109
人工智能·swiftui·swift
汉秋6 天前
SwiftUI动画之使用 navigationTransition(.zoom) 实现 Hero 动画
ios·swiftui