You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

SwiftUI开发:如何在Sheet上方固定位置放置跟随移动的按钮?

实现苹果地图式跟随Sheet移动的顶部控件

要让控件跟随底部Sheet同步移动,核心是将控件与Sheet的位置变化绑定,以下是两种可行实现方案:

方案一:基于预设Detent状态同步位置

适合使用固定高度档位(如medium、large、自定义高度)的Sheet场景:

  1. 定义绑定变量跟踪当前Sheet的档位:
@State private var selectedDetent: PresentationDetent = .height(80)
  1. 在视图中添加跟随控件,并根据档位计算偏移量:
struct ContentView: View {
    @State private var selectedDetent: PresentationDetent = .height(80)
    
    var body: some View {
        ZStack {
            HomeView()
            
            // 跟随Sheet移动的控件组(示例:Look Around按钮+AQI显示)
            HStack {
                Button(action: {}) {
                    Image(systemName: "binoculars")
                        .padding()
                        .background(.white)
                        .cornerRadius(12)
                }
                
                Spacer()
                
                Text("AQI 42 良")
                    .padding(.horizontal, 16)
                    .padding(.vertical, 8)
                    .background(.white)
                    .cornerRadius(12)
            }
            .padding(.horizontal, 16)
            .offset(y: calculateOffset(for: selectedDetent))
            
            .sheet(isPresented: .constant(true)) {
                ActivityView()
                    .presentationDetents([.medium, .large, .height(80)], selection: $selectedDetent)
                    .presentationCornerRadius(Constants.cornerRadius)
                    .presentationBackgroundInteraction(.enabled)
                    .interactiveDismissDisabled(true)
            }
        }
    }
    
    // 根据当前档位计算控件垂直偏移量
    private func calculateOffset(for detent: PresentationDetent) -> CGFloat {
        switch detent {
        case .height(80):
            return -40 // Sheet处于最低位时的偏移
        case .medium:
            return -200 // Sheet处于中间位时的偏移
        case .large:
            return -400 // Sheet处于最高位时的偏移
        default:
            return -40
        }
    }
}

方案二:实时监听Sheet拖动进度(精准跟随)

支持拖动Sheet过程中,控件实时同步位置:

  1. 创建监听Sheet进度的桥接视图:
struct SheetProgressView: UIViewControllerRepresentable {
    @Binding var progress: CGFloat
    
    func makeUIViewController(context: Context) -> UIViewController {
        let vc = UIViewController()
        vc.view.isHidden = true
        return vc
    }
    
    func updateUIViewController(_ uiViewController: UIViewController, context: Context) {
        guard let sheet = uiViewController.presentingViewController?.presentedViewController as? UISheetPresentationController else { return }
        sheet.delegate = context.coordinator
    }
    
    func makeCoordinator() -> Coordinator {
        Coordinator(self)
    }
    
    class Coordinator: NSObject, UISheetPresentationControllerDelegate {
        let parent: SheetProgressView
        
        init(_ parent: SheetProgressView) {
            self.parent = parent
        }
        
        func sheetPresentationController(_ sheetPresentationController: UISheetPresentationController, didChangeScrollEdgeAppearance appearance: UIScrollEdgeAppearance?) {
            // 计算Sheet拖动进度(需根据屏幕尺寸调整逻辑)
            let screenHeight = UIScreen.main.bounds.height
            let sheetTopY = sheetPresentationController.presentedViewController.view.frame.minY
            parent.progress = 1 - (sheetTopY / screenHeight)
        }
    }
}
  1. 在主视图中集成进度监听,同步控件位置:
struct ContentView: View {
    @State private var sheetProgress: CGFloat = 0
    
    var body: some View {
        ZStack {
            HomeView()
            
            // 跟随控件组
            HStack {
                Button(action: {}) {
                    Image(systemName: "binoculars")
                        .padding()
                        .background(.white)
                        .cornerRadius(12)
                }
                
                Spacer()
                
                Text("AQI 42 良")
                    .padding(.horizontal, 16)
                    .padding(.vertical, 8)
                    .background(.white)
                    .cornerRadius(12)
            }
            .padding(.horizontal, 16)
            .offset(y: -sheetProgress * 360) // 系数根据实际UI调整
            
            .sheet(isPresented: .constant(true)) {
                ActivityView()
                    .presentationDetents([.medium, .large, .height(80)])
                    .presentationCornerRadius(Constants.cornerRadius)
                    .presentationBackgroundInteraction(.enabled)
                    .interactiveDismissDisabled(true)
                    .background(SheetProgressView(progress: $sheetProgress))
            }
        }
    }
}

注意事项

  • 偏移量数值需根据你的UI设计微调,确保控件始终处于Sheet顶部的合理位置。
  • 可给控件添加与Sheet一致的阴影效果,强化"附着"在Sheet上的视觉感受。

内容的提问来源于stack exchange,提问作者Jon

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.21 02:22:37