【问题标题】:Update Specific Button Image in UITableView Cell更新 UITableView 单元格中的特定按钮图像
【发布时间】:2021-04-22 05:57:12
【问题描述】:

我正在尝试向我的“喜欢”按钮添加一个操作。因此,当用户点击单元格中的心形 UIButton 时,他们点击的单元格中的心形会更新为粉红色的心形,表明他们喜欢它。但相反,它喜欢他们轻敲的心脏,以及他们没有与之互动的不同细胞中的另一颗随机心脏。我整天都在做这件事,任何帮助都将不胜感激。例如,如果我喜欢/点击我的心 UIButton,我点击的按钮图像会更新,但是当我向下滚动时,会从同一个单元格按钮点击另一个随机的心更新。

此外,当我滚动并且单元格离开视图并向上滚动时,图像会返回到不同的状态,并且其他类似的按钮会变得喜欢。

【问题讨论】:

标签: swift uitableview cell nsindexpath indexpath


【解决方案1】:

为您的按钮状态保留数据模型

试试下面的代码

struct TableModel {
    var isLiked: Bool
}

class ViewController: UIViewController, UITableViewDelegate, UITableViewDataSource {

var dataSource: [TableModel] = []

@IBOutlet var tableView: UITableView!

override func viewDidLoad() {
    super.viewDidLoad()
    overrideUserInterfaceStyle = .light
    dataSource = Array(repeating: TableModel(isLiked: false), count: 20)
        self.tableView.delegate = self
        self.tableView.dataSource = self
        self.tableView.showsVerticalScrollIndicator = false
        self.tableView.reloadData()
}

func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
    tableView.deselectRow(at: indexPath, animated: true)
    
}

func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
    dataSource.count
}

@objc func buttonSelected(_ sender: UIButton) {
    
    dataSource[sender.tag].isLiked = !dataSource[sender.tag].isLiked
    let indexPath = IndexPath(row: sender.tag, section: 0)
    tableView.reloadRows(at: [indexPath], with: .automatic)
}

func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
    let cell = tableView.dequeueReusableCell(withIdentifier: "cell", for: indexPath) as! TableViewCell
    
    cell.likeBtn.tag = indexPath.row
    cell.likeBtn.addTarget(self, action: #selector(buttonSelected(_:)), for: .touchUpInside)
    let isLiked = dataSource[indexPath.row].isLiked
    if isLiked {
        cell.likeBtn.setImage(UIImage(named: "liked"), for: UIControl.State.normal)
    } else {
        //set unlike image
    }
    return cell
}

}

【讨论】:

  • 这就是答案,谢谢。你能向我解释它是什么以及它是如何一步一步发生的吗?只是为了让我能够接受更多的教育,而不仅仅是复制和粘贴 :) 如果你可以在你添加的代码中添加 cmets。
  • 当用户退出应用程序并稍后返回时,本地保存单元格内存的最佳方法是什么。这样同样喜欢的单元格仍然喜欢吗?
【解决方案2】:

目前,您有一个硬编码的行数,但无论如何您都需要一个带有数据模型的数据源。当您按下按钮时,您必须保存特定行的按钮状态。我建议你先创建一个模型。

在这里,我提供了一种简单(但足够灵活)的方法来做到这一点。我还没有调试它,但它应该可以工作,你可以看到这个想法。我希望这会有所帮助。

创建细胞模型

struct CellViewModel {
    let title: String
    var isLiked: Bool
    // Add other properties you need for the cell, image, etc.
}

更新单元格类

最好在单元格类中处理顶部操作。要在控制器上处理此操作,您可以像我一样关闭或委托。

// Create a delegate protocol
protocol TableViewCellDelegate: AnyObject {
    func didSelectLikeButton(isLiked: Bool, forCell cell: TableViewCell)
}

class TableViewCell: UITableViewCell {
    // add a delegate property
    weak var delegate: TableViewCellDelegate?
    
    @IBOutlet var titleTxt: UILabel!
    @IBOutlet var likeBtn: UIButton!
    //...
    
    override func awakeFromNib() {
        super.awakeFromNib()
        // You can add target here or an action in the Storyboard/Xib
        likeBtn.addTarget(self, action: #selector(likeButtonSelected), for: .touchUpInside)
    }

    /// Method to update state of the cell
    func update(with model: CellViewModel) {
        titleTxt.text = model.title
        likeBtn.isSelected = model.isLiked
        // To use `isSelected` you need to set different images for normal state and for selected state
    }
        
    @objc private func likeButtonSelected(_ sender: UIButton) {
        sender.isSelected.toggle()
        delegate?.didSelectLikeButton(isLiked: sender.isSelected, forCell: self)
    }
}

添加一个模型数组并使用它

这是 ViewController 的更新类,使用了模型。

class ViewController: UIViewController, UITableViewDelegate, UITableViewDataSource {
    // Provide a list of all models (cells)
    private var cellModels: [CellViewModel] = [
        CellViewModel(title: "Title 1", isLiked: false),
        CellViewModel(title: "Title 2", isLiked: true),
        CellViewModel(title: "Title 3", isLiked: false)
    ]
    
    @IBOutlet var tableView: UITableView!
    
    override func viewDidLoad() {
        super.viewDidLoad()
        overrideUserInterfaceStyle = .light
        
        self.tableView.delegate = self
        self.tableView.dataSource = self
        self.tableView.showsVerticalScrollIndicator = false
        self.tableView.reloadData()
    }
    
    func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
        tableView.deselectRow(at: indexPath, animated: true)
    }
    
    func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
        // return count of cell models
        return cellModels.count
    }
    
    func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
        let cell = tableView.dequeueReusableCell(withIdentifier: "cell", for: indexPath) as! TableViewCell
        
        let model = cellModels[indexPath.row]

        // call a single method to update the cell UI
        cell.update(with: model)
         
        // and you need to set delegate in order to handle the like button selection
        cell.delegate = self
        
        return cell
    }
}

extension ViewController: TableViewCellDelegate {
    func didSelectLikeButton(isLiked: Bool, forCell cell: TableViewCell) {
        // get an indexPath of the cell which call this method
        guard let indexPath = tableView.indexPath(for: cell) else {
            return
        }

        // get the model by row
        var model = cellModels[indexPath.row]

        // save the updated state of the button into the cell model
        model.isLiked = isLiked
        
        // and set the model back to the array, since we use struct
        cellModels[indexPath.row] = model
    }
}

【讨论】:

  • 我不能走这条路,因为我正在从 api 中提取数据,并且在加载数据之前永远不会知道我将拥有多少行。无论如何都要这样做?
  • 在我的代码中,数组cellModels 只是一个示例。我已经提供了如何处理“喜欢”按钮的方法。您可能需要更新和扩展此代码。关于 API - 从 API 中提取数据后,您必须将其保存到 cellModels 并调用 tableView.reloadData()。其他一切都会像现在一样工作。
  • 当我使用 UISearchBar 并拥有具有正确按钮状态的正确单元格时,此代码是否有效?
  • 是的,正确的点赞按钮状态将按原样工作。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2018-04-19
相关资源
最近更新 更多