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

SwiftUI中如何在ForEach第4项点击时跳转付费墙页面

SwiftUI ForEach 内容权限控制实现方案

核心逻辑梳理

要实现需求,关键是获取元素在数组中的索引,结合用户订阅状态做跳转判断:

  • 已订阅高级权限:所有项直接跳转详情页
  • 未订阅:前3项(索引0、1、2)正常跳转,第4项及以后(索引≥3)跳转付费墙

修改后的完整代码

struct ContentView: View {
    @Environment(ViewModel.self) var viewModel
    @Environment(PaywallViewModel.self) var paywallViewModel
    @Bindable var vm: ViewModel

    init() {
        self.vm = ViewModel() // 根据实际ViewModel初始化逻辑调整
    }
    
    var body: some View {
        NavigationStack {
            GeometryReader { geo in
                ScrollView(showsIndicators: false) {
                    // 改用带索引的枚举形式遍历数组
                    ForEach(Array(viewModel.filteredDinos.enumerated()), id: \.element.id) { index, predator in
                        VStack {
                            NavigationLink(destination: getDestination(for: predator, at: index)) {
                                withAnimation {
                                    PredatorCard(predator: predator)
                                        // 给非订阅用户的受限项添加锁标识
                                        .overlay(
                                            Group {
                                                if !paywallViewModel.hasPremiumSubscription && index >= 3 {
                                                    Image(systemName: "lock")
                                                        .padding(8)
                                                        .background(Color.black.opacity(0.7))
                                                        .foregroundColor(.white)
                                                        .cornerRadius(8)
                                                        .position(x: geo.size.width - 20, y: 20)
                                                }
                                            }
                                        )
                                }
                            }
                        }
                        .frame(width: geo.size.width)
                    }
                }
                .navigationTitle("Jurassic Journey")
                .searchable(text: $vm.searchText)
                .autocorrectionDisabled()
                .toolbar {
                    ToolbarItem(placement: .topBarLeading) {
                        Button(action: {
                            withAnimation {
                                viewModel.alphabetical.toggle()
                            }
                        }) {
                            Image(systemName: viewModel.alphabetical ? "film" : "textformat")
                                .symbolEffect(.bounce, value: viewModel.alphabetical)
                        }
                    }
                    
                    ToolbarItem(placement: .topBarTrailing) {
                        Menu {
                            Picker("Filter", selection: $vm.currentTypeSelection.animation()) {
                                ForEach(PredatorType.allCases) { type in
                                    Label(type.rawValue.capitalized, systemImage: type.icon)
                                }
                            }
                        } label: {
                            Image(systemName: "slider.horizontal.3")
                        }
                    }
                }
            }
        }
        .navigationSplitViewStyle(.automatic)
        .preferredColorScheme(.dark)
    }
    
    // 抽离跳转逻辑,简化body代码
    private func getDestination(for predator: Predator, at index: Int) -> some View {
        if paywallViewModel.hasPremiumSubscription {
            return AnyView(PredatorDetail(predator: predator, position: .camera(MapCamera(centerCoordinate: predator.location, distance: 2000))))
        } else {
            return index < 3 
                ? AnyView(PredatorDetail(predator: predator, position: .camera(MapCamera(centerCoordinate: predator.location, distance: 2000)))) 
                : AnyView(PaywallView()) // 替换为你的付费墙页面
        }
    }
}

关键修改点说明

  1. 带索引遍历:通过Array(viewModel.filteredDinos.enumerated())将数组转为带索引的元组集合,直接获取元素位置index
  2. 条件跳转:把跳转目标判断逻辑抽离到getDestination方法,根据订阅状态和索引返回对应页面
  3. 视觉提示:给非订阅用户的第4项及以后卡片添加锁图标,明确告知内容需要订阅解锁
  4. 语法修正:将@Bindable属性移到body外,符合SwiftUI语法规范

注意事项

  • 确保PaywallViewModel中存在hasPremiumSubscription属性,用于判断用户订阅状态
  • 将代码中的PaywallView()替换为你实际的付费墙页面结构体
  • 若ViewModel初始化需要依赖环境,调整init方法实现逻辑

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.17 20:04:55