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

如何判断swipeActions()所在容器类型,以动态切换原生/自定义滑动操作方案?

如何判断swipeActions()所在容器类型,以动态切换原生/自定义滑动操作方案?

其实SwiftUI并没有直接提供API让我们直接检测当前View到底在List还是ScrollView里,但我们可以通过自定义环境变量的方式,给容器打个标记,让子View能“感知”到自己的容器类型,从而动态切换滑动方案。下面给你一步步拆解怎么做:

  • 第一步:定义容器类型的环境键
    先创建一个枚举来区分不同的容器类型,再自定义一个环境键用来传递这个信息:

    enum ContainerType {
        case list, scrollView, none
    }
    
    struct ContainerTypeKey: EnvironmentKey {
        static let defaultValue: ContainerType = .none
    }
    
    extension EnvironmentValues {
        var containerType: ContainerType {
            get { self[ContainerTypeKey.self] }
            set { self[ContainerTypeKey.self] = newValue }
        }
    }
    
  • 第二步:给List和ScrollView添加标记扩展
    给List和ScrollView分别添加一个修饰符,设置对应的环境值,这样它们内部的子View就能拿到这个标记:

    extension List {
        func setContainerType() -> some View {
            self.environment(\.containerType, .list)
        }
    }
    
    extension ScrollView {
        func setContainerType() -> some View {
            self.environment(\.containerType, .scrollView)
        }
    }
    
  • 第三步:在ItemView中动态切换滑动方案
    在你的ItemView里读取环境变量,根据容器类型决定用原生swipeActions还是自定义方案:

    struct ItemView: View {
        @Environment(\.containerType) private var containerType
        
        let leading: [SwipeActionItem] // 替换成你实际的滑动按钮数据类型
        let trailing: [SwipeActionItem]
        let allowsFullSwipeLeading: Bool
        let allowsFullSwipeTrailing: Bool
        
        var body: some View {
            Text("你的Item内容")
                .applySwipeActions()
        }
        
        @ViewBuilder
        func applySwipeActions() -> some View {
            switch containerType {
            case .list:
                // 在List里用原生swipeActions
                self
                    .swipeActions(edge: .leading, allowsFullSwipe: allowsFullSwipeLeading) {
                        buttons(items: leading, side: "leading")
                    }
                    .swipeActions(edge: .trailing, allowsFullSwipe: allowsFullSwipeTrailing) {
                        buttons(items: trailing, side: "trailing")
                    }
            case .scrollView, .none:
                // 在ScrollView或未知容器里用自定义滑动方案
                CustomSwipeView(content: self, leadingActions: leading, trailingActions: trailing)
            }
        }
        
        // 你的按钮生成逻辑保持不变
        @ViewBuilder
        func buttons(items: [SwipeActionItem], side: String) -> some View {
            ForEach(items) { item in
                Button(action: item.action) {
                    Label(item.title, systemImage: item.icon)
                }
                .tint(item.tintColor)
            }
        }
    }
    
  • 第四步:使用时给容器加上标记修饰符
    最后在使用List和ScrollView的时候,记得加上我们定义的setContainerType()修饰符:

    // List容器的用法
    List {
        ForEach(yourItems) { item in
            ItemView(leading: leadingActions, trailing: trailingActions, 
                     allowsFullSwipeLeading: true, allowsFullSwipeTrailing: false)
        }
    }
    .setContainerType()
    
    // ScrollView容器的用法
    ScrollView {
        VStack {
            ForEach(yourItems) { item in
                ItemView(leading: leadingActions, trailing: trailingActions, 
                         allowsFullSwipeLeading: true, allowsFullSwipeTrailing: false)
            }
        }
    }
    .setContainerType()
    

这个方案的核心是利用SwiftUI的环境变量传递容器信息,既灵活又符合SwiftUI的设计思想,后续如果需要支持其他容器类型,只需要扩展枚举和对应的容器扩展就可以了。

内容来源于stack exchange

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.04.08 11:15:29