如何判断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
相关产品推荐
相关产品推荐

