我如何在 UITableViewCell 或 UICollectionViewCell 中为 UIButton 编写一个扩展,它只影响它所在的单元格?
Posted
技术标签:
【中文标题】我如何在 UITableViewCell 或 UICollectionViewCell 中为 UIButton 编写一个扩展,它只影响它所在的单元格?【英文标题】:How can i write an extension for UIButton in UITableViewCell or UICollectionViewCell that only affects the cell which it is inside? 【发布时间】:2019-05-24 07:59:37 【问题描述】:如您所知,当我们在可重复使用的单元格中声明一个按钮时,它会在滚动 5 或 6 个单元格后重复 UI。 prepareToReuse() 方法只重置 UI,但是为了保持 UI 上的变化,我们需要声明一个字典,
prepareToReuse() 方法只重置 UI,但是;为了保持 UI 的变化 1) 我们需要声明一个字典数组 2)用我们需要的单元格计数的默认值填充该字典 3)改变与我们的单元格相同索引的元素的值 4)在重用单元格时检查我们是否更改了默认值
import UIKit
//defining a enum to track cell state
enum CellState
case selected
case unselected
init()
self = .unselected
class yourCell: UICollectionViewCell
@IBOutlet weak var yourBtn: UIButton!
// creating our func
var buttonAction: (() -> ())?
override func awakeFromNib()
super.awakeFromNib()
@IBAction func sliderAction(_ sender: UISlider)
// defining our func where we want to use it
buttonAction()
// inside our viewController
import UIKit
class yourViewController: UIViewController, UICollectionViewDelegate, UICollectionViewDataSource
@IBOutlet weak var collectionView: UICollectionView!
// you data source that you fill the cells
var yourDataArray: [yourDataSource]()
// the array that will hold status of our cells
private var cellStateArray: [CellState]?
override func viewDidLoad()
super.viewDidLoad()
//confirming our delegate and dataSource
collectionView.dataSource = self
collectionView.delegate = self
//filling your cellStateArray as many as your cell count
self.cellStateArray = Array(repeating: .unselected, count: self.yourDataArray!.count )
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int
if yourDataArray?.isEmpty == false
return yourDataArray!.count
else
print("Caution yourDataArray IS EMPTY")
return 0
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "yourCell", for: indexPath) as! yourCell
// checking your button selected or not while reuse it (while scrolling)
if cellStateArray![indexPath.row] == .selected
cell.yourBtn.backgroundColor = .red
else
cell.yourBtn.backgroundColor = .blue
cell.buttonAction =
//calling button function
button_Select(_ sender: cell.yourBtn, cellStateArray: cellStateArray, indexPath: IndexPath)
// Defining the function what you want to do with your button in each cell
func button_Select(_ sender: UIButton, cellStateArray: [CellState], indexPath: IndexPath )
sender.isSelected = !sender.isSelected
if sender.isSelected
sender.backgroundColor = .red
//setting value when your button selected
cellStateArray[indexPath.row] = .selected
else
sender.backgroundColor = .blue
//setting value when your button unselected
cellStateArray[indexPath.row] = .unselected
collectionView.reloadData()
如果有人需要使用它,我也提到了我自己的方法,但正如您所见,它的路还很长。我的问题是我们是否可以为 UIButton 定义一个扩展来完成相同的工作,或者是否有更短更好的方法来使用它。跟踪 reusableCells 中的重复按钮,如“按钮、开关、复选框等”。有问题不知道为什么苹果不为它做点什么。如果有人告诉我更好的方法,我会很高兴。谢谢。
【问题讨论】:
为什么不在单元格内添加这个按钮?然后使用委托将动作传递给控制器 问题是单元格是可重复使用的,因此当您进行更改时,它会在 6 或 7 个单元格后重复,但在委托和关闭方式中功能不会受到影响。 【参考方案1】:检查此代码,我已将您的数据源视为模型而不是字典,您可以轻松制作。
class yourCell: UICollectionViewCell
@IBOutlet weak var yourBtn: UIButton!
// creating our func
var reloadData: (() -> ())?
var model = yourDataSource()
override func awakeFromNib()
super.awakeFromNib()
@IBAction func sliderAction(_ sender: UISlider)
self.model.isSelected = !self.model.isSelected
reloadData?()
func setCellData(model:yourDataSource)
self.model = model
if model.isSelected
yourBtn.backgroundColor = .red
else
yourBtn.backgroundColor = .blue
// inside our viewController
import UIKit
class yourViewController: UIViewController
@IBOutlet weak var collectionView: UICollectionView!
// you data source that you fill the cells
var yourDataArray = [yourDataSource]() // considering this as model and has isSelected property (default false)
override func viewDidLoad()
super.viewDidLoad()
//confirming our delegate and dataSource
collectionView.dataSource = self
collectionView.delegate = self
//fill your model here or pass data as u want
extension yourViewController : UICollectionViewDelegate, UICollectionViewDataSource
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int
if yourDataArray?.isEmpty == false
return yourDataArray!.count
else
print("Caution yourDataArray IS EMPTY")
return 0
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell
let model = self.yourDataArray[indexPath.row]
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "yourCell", for: indexPath) as! yourCell
cell.setCellData(model: model)
cell.reloadData =
//reload full collection view or single item
self.collectionView.reloadData()
return cell
【讨论】:
感谢您的回答。如果你有一个模型,定义一个变量来建模像 var cellButtonState: Bool = false 更容易控制你的 UI 和你的按钮是否被选中,但是如果你没有模型,你应该使用我提到的方式多于。所以我的问题是可以仅使用扩展来跟踪您的按钮,而不是在模型或字典中定义变量,并且可以在单元格中的所有按钮上执行该扩展 @GökhanSayılgan 是的,我正在谈论它我的变量名称是模型中的 isSelected。我们只需要维护单个变量。以上是关于我如何在 UITableViewCell 或 UICollectionViewCell 中为 UIButton 编写一个扩展,它只影响它所在的单元格?的主要内容,如果未能解决你的问题,请参考以下文章
多行 UILabel 在 UITableViewCell 内的较小 iPhone 中截断或剪切字符串
在 UITableViewCell 中添加 UICollectionView 后 UI 突然发生变化
UITableViewCell 上的 UIProgressView
如何在 UITableViewCell 中左对齐或右对齐 UILabel
我如何在 UITableViewCell 或 UICollectionViewCell 中为 UIButton 编写一个扩展,它只影响它所在的单元格?