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

如何通过应用内购实现UITableView指定行的锁定与解锁?

实现UITableView部分行默认解锁、其余行锁定的方案

嘿,我完全懂你的需求——想要让列表里前两行默认开放,第三行及之后的内容(哪怕超过12行)默认锁定,只有用户完成内购后才解锁全部内容对吧?咱们来调整你的代码就能搞定,下面是具体的修改方案:

问题分析

你当前的代码逻辑是要么全锁、要么全解锁,没有区分哪些行是默认免费的。咱们需要添加对行索引的判断,来实现部分行免费开放的效果。

修改步骤&代码实现

1. 调整单元格锁定状态的显示逻辑

在cellForRowAt方法里,我们要区分免费行和付费行:

  • 已购买用户:所有行都隐藏锁定图标
  • 未购买用户:前两行隐藏锁定图标,其余行显示

2. 调整行点击的跳转逻辑

在didSelectRowAt方法里:

  • 点击前两行:直接跳转到对应内容,无需判断购买状态
  • 点击第三行及以后:检查购买状态,未购买则跳转到解锁页面,已购买则正常跳转

下面是修改后的完整代码:

import Foundation
import UIKit

class TrappingVC: UIViewController {
    @IBOutlet weak var buildingTableView: UITableView!
    @IBOutlet weak var settingsButtonItem: UIBarButtonItem!
    
    var trapping: [CellObject] = []
    // 注意:如果列表行数超过segueIdentifiers的数量,这里要对应扩展数组,避免越界
    var segueIdentifiers = ["a", "b", "c", "d"] // 示例:对应前四行的segue
    
    //VIEWDIDLOAD
    override func viewDidLoad() {
        super.viewDidLoad()
        //LOAD ARRARYS
        trapping = createBuildArray()
        buildingTableView.delegate = self
        buildingTableView.dataSource = self
        self.buildingTableView.rowHeight = 100.0
        buildingTableView.tableFooterView = UIView()
        //CELL SEPARATORS
        buildingTableView.layoutMargins = UIEdgeInsets.zero
        buildingTableView.separatorInset = UIEdgeInsets.zero
        buildingTableView.separatorColor = UIColor.black
        buildingTableView.register(UINib.init(nibName: "TrappingCell", bundle: nil), forCellReuseIdentifier: "TrappingCell")
        settingsButtonItem.image = UIImage(named: "Settings")
    }
    
    @IBAction func showSettingsClicked(_ sender: Any) {
        performSegue(withIdentifier: "showSettings", sender: self)
    }
    
    //CREATE ARRAY OF BASIC LESSONS
    func createBuildArray() -> [CellObject]{
        var tempTrapping: [CellObject] = []
        let trapping1 = CellObject(image: #imageLiteral(resourceName: "Yellow"), title: "Below")
        let trapping2 = CellObject(image: #imageLiteral(resourceName: "Yellow"), title: "Side")
        let trapping3 = CellObject(image: #imageLiteral(resourceName: "Yellow"), title: "Above")
        // 可以继续添加更多行示例
        let trapping4 = CellObject(image: #imageLiteral(resourceName: "Yellow"), title: "Advanced 1")
        let trapping5 = CellObject(image: #imageLiteral(resourceName: "Yellow"), title: "Advanced 2")
        tempTrapping.append(trapping1)
        tempTrapping.append(trapping2)
        tempTrapping.append(trapping3)
        tempTrapping.append(trapping4)
        tempTrapping.append(trapping5)
        return tempTrapping
    }
}

//TABLE
extension TrappingVC: UITableViewDataSource, UITableViewDelegate {
    func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
        return trapping.count
    }
    
    func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
        let trappings = trapping[indexPath.row]
        let cell = tableView.dequeueReusableCell(withIdentifier: "TrappingCell") as! TrappingCell
        cell.trappingTitle.text = trappings.title
        cell.trappingImage.image = trappings.image
        
        // 判断是否已购买
        let isPurchased = UserDefaults.standard.bool(forKey: "payment")
        // 定义免费行的范围:前两行(index从0开始,所以row < 2)
        let isFreeRow = indexPath.row < 2
        
        // 设置锁定图标显示状态
        if isPurchased || isFreeRow {
            cell.lockedImage.isHidden = true
        } else {
            cell.lockedImage.isHidden = false
        }
        
        cell.layoutIfNeeded()
        cell.layoutMargins = UIEdgeInsets.zero
        return cell
    }
    
    func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
        let isPurchased = UserDefaults.standard.bool(forKey: "payment")
        let isFreeRow = indexPath.row < 2
        
        if isFreeRow || isPurchased {
            // 免费行或已购买,正常跳转
            // 注意:要确保segueIdentifiers数组的长度 >= 当前列表行数,避免数组越界
            if indexPath.row < segueIdentifiers.count {
                performSegue(withIdentifier: segueIdentifiers[indexPath.row], sender: self)
            }
        } else {
            // 未购买且是付费行,跳转到解锁页面
            let storyboard = UIStoryboard(name: "Main", bundle: nil)
            let controller = storyboard.instantiateViewController(withIdentifier: "UnlockContentVC")
            self.navigationController?.pushViewController(controller, animated: true)
        }
        
        tableView.deselectRow(at: indexPath, animated: true)
    }
}

关键改动说明

  1. 简化购买状态判断:用UserDefaults.standard.bool(forKey: "payment")替代原来的可选绑定,更简洁,默认值为false(如果key不存在的话)。
  2. 新增免费行判断:用indexPath.row < 2明确前两行是免费的,你可以根据需求修改这个数值(比如想要前3行免费就改成row < 3)。
  3. 完善跳转逻辑:确保免费行不管购买状态都能正常跳转,付费行只有购买后才能访问。
  4. 数组越界防护:在跳转时判断indexPath.row < segueIdentifiers.count,避免当列表行数超过segue数组长度时崩溃。

额外提醒

  • 确保内购成功后,正确调用UserDefaults.standard.set(true, forKey: "payment")并同步,这样购买状态才能被正确读取。
  • 如果后续要调整免费行的数量,只需要修改isFreeRow的判断条件即可,非常灵活。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.11 08:52:57