通过在 tableView 单元格(expand/collapse 单元格)中单击按钮显示隐藏标签
Show hidden label by button click inside tableView Cell (expand/collapse cell)
我有一个包含标签的 stackView(垂直),底部描述标签默认隐藏。我在单元格的右侧实现了一个箭头按钮。通过单击按钮,我只想显示隐藏的描述标签,stackView 应该会自动展开并使单元格变大。这是我实现可扩展单元的基本想法。
所以这是我用来获得所需结果的代码:
@objc func downArrowButtonClicked(_ sender: UIButton){
let indexPath = IndexPath(row: sender.tag, section: 0)
selectedIndex = indexPath
selectedCellIndex = sender.tag
isDescHidden = !isDescHidden
tableView.reloadRows(at: [indexPath], with: .automatic)
}
以上是单击单元格内按钮的代码。我想到了重新加载该特定索引的想法。我创建了一个名为 selectedCellIndex
的变量,我在 cellForRowAt
方法中使用它来进行一些更改。
我还在 viewDidLayoutSubviews() 中实现了一些代码,因为当我第一次单击单元格时没有完全展开。以防万一:
override func viewDidLayoutSubviews() {
super.viewDidLayoutSubviews()
let indexPath = selectedIndex
tableView.reloadRows(at: [indexPath ?? IndexPath(row: 0, section: 0)], with: .automatic)
}
并在 willDisplay
方法中调用它,最终解决了单元格扩展问题:
func tableView(_ tableView: UITableView, willDisplay cell: UITableViewCell, forRowAt indexPath: IndexPath) {
viewDidLayoutSubviews()
}
这是我的 cellForRowAt
函数:
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "CustomTableViewCell", for: indexPath) as! CustomTableViewCell
if indexPath.row == 0 {
cell.lblTitle.text = "Title 1"
cell.lblDesc.text = "Desc 1"
}
else if indexPath.row == 1 {
cell.lblTitle.text = "Title 2"
cell.lblDesc.text = "Desc 2"
}
else {
cell.lblTitle.text = "Title 3"
cell.lblDesc.text = "Desc 3"
}
if selectedCellIndex != nil {
if isDescHidden == false {
if cell.isDescHidden == true {
cell.lblDesc.isHidden = false
cell.btnArrow.setImage(UIImage(systemName: "chevron.up"), for: .normal)
}
else {
cell.lblDesc.isHidden = true
cell.btnArrow.setImage(UIImage(systemName: "chevron.down"), for: .normal)
}
}
else {
if cell.isDescHidden == true {
cell.lblDesc.isHidden = true
cell.btnArrow.setImage(UIImage(systemName: "chevron.down"), for: .normal)
}
else {
cell.lblDesc.isHidden = false
cell.btnArrow.setImage(UIImage(systemName: "chevron.up"), for: .normal)
}
}
cell.isDescHidden = !cell.isDescHidden
}
cell.btnArrow.tag = indexPath.row
cell.btnArrow.addTarget(self, action: #selector(downArrowButtonClicked(_:)), for: .touchUpInside)
return cell
}
从上面的代码可以看出,这种方法太混乱了。 isDescHidden
变量在主视图控制器和 table 视图单元格 class 中都有定义,我试图同时使用它们来展开或折叠特定的单元格。但是第一次它工作但如果我有 3 个单元格展开,折叠按钮单击不起作用 1-2 单击然后工作。
对于这种问题有更好的方法吗?或者有什么方法可以直接从 @objc func downArrowButtonClicked(_ sender: UIButton)
函数设置 cell.isDescHidden
值?所以我可以在 cellForRowAt
函数中使用它吗?
如果我可以直接从中更改单元格变量,我会很高兴。
使用以下函数自动设置行高,并为您的 stackView
提供 top
和 bottom
约束
func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
return UITableView.automaticDimension
}
这是我的 CustomCell
class CustomCell: UITableViewCell {
@IBOutlet weak var titleCell: UILabel!
@IBOutlet weak var detail: UILabel!
@IBOutlet weak var arrowButton: UIButton!
let upArrow = UIImage(systemName: "chevron.up.circle.fill")
let downArrow = UIImage(systemName: "chevron.down.circle.fill")
var onArrowClick: ((UIButton)->())!
@IBAction func handleArrowButton(sender: UIButton){
onArrowClick(sender)
}
func updateArrowImage(expandStatus: Bool){
arrowButton.setImage(expandStatus ? downArrow : upArrow, for: .normal)
}
}
示例数据
let data = [
["Nothing", "description is very long description is very long description is very long description is very "],
["Nothing", "description is very long "],
["Nothing", "description is very long "],
["Nothing", "description is very long "],
["Nothing", "description is very long "]
]
var eachCellStatus: [Bool] = []
@IBOutlet weak var tableView: UITableView!
override func viewDidLoad() {
super.viewDidLoad()
tableView.dataSource = self
tableView.delegate = self
for _ in data {
eachCellStatus.append(true)
}
}
TableView 方法是这样的
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return data.count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "cell") as! CustomCell
cell.titleCell.text = data[indexPath.row][0]
cell.detail.text = data[indexPath.row][1]
cell.detail.isHidden = eachCellStatus[indexPath.row]
cell.updateArrowImage(expandStatus: self.eachCellStatus[indexPath.row])
cell.onArrowClick = { button in
self.eachCellStatus[indexPath.row].toggle()
cell.updateArrowImage(expandStatus: self.eachCellStatus[indexPath.row])
tableView.reloadRows(at: [indexPath], with: .automatic)
}
return cell
}
首先创建一个模型来将数据显示到单元格中。你必须保留细胞的状态。
struct CellData {
var title: String
var details: String
var isExpanded: Bool
}
在 CustomTableViewCell
中为 cellData 添加一个 属性 并从中分配 Outlet
s 数据。同时创建一个 protocol
以从 UIViewController
重新加载 row
protocol CustomTableViewCellDelegate {
func reloadRow(sender: CustomTableViewCell, flag: Bool)
}
class CustomTableViewCell: UITableViewCell {
@IBOutlet weak var titleLabel: UILabel!
@IBOutlet weak var detailsLabel: UILabel!
@IBOutlet weak var showButton: UIButton!
var indexPath: IndexPath?
var delegate: CustomTableViewCellDelegate?
var data: CellData? {
didSet {
if let data = data {
if data.isExpanded == false {
detailsLabel.isHidden = true
showButton.setImage(UIImage(systemName: "chevron.down"), for: .normal)
}else {
detailsLabel.isHidden = true
showButton.setImage(UIImage(systemName: "chevron.up"), for: .normal)
}
titleLabel.text = data.title
detailsLabel.text = data.details
}
}
}
override func awakeFromNib() {
super.awakeFromNib()
titleLabel.text = nil
detailsLabel.text = nil
}
@IBAction func showButtonAction(_ sender: UIButton) {
if var data = data {
data.isExpanded.toggle()
delegate?.reloadRow(cell: self, flag: data.isExpanded)
}
}
}
在UIViewController
中添加一个CellData
类型的数组。您可以在 viewDidLoad()
方法中分配它的数据。
var tableData: [CellData]
修改 numberOfRowsInSection()
和 cellForRow()
方法,如 bleow。
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return tableData.count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "CustomTableViewCell", for: indexPath) as! CustomTableViewCell
cell.data = tableData[indexPath.row]
cell.delegate = self
return cell
}
func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
return UITableView.automaticDimension
}
然后确认 CustomTableViewCellDelegate
协议到 UIViewController
extension ViewController: CustomTableViewCellDelegate {
func reloadRow(sender: CustomTableViewCell, isExpanded: Bool) {
guard let tappedIndexPath = tableView.indexPath(for: sender) else { return }
tableData[tappedIndexPath.row].isExpanded = isExpanded
tableView.reloadRows(at: [indexPath], with: UITableView.RowAnimation.automatic)
}
}
我有一个包含标签的 stackView(垂直),底部描述标签默认隐藏。我在单元格的右侧实现了一个箭头按钮。通过单击按钮,我只想显示隐藏的描述标签,stackView 应该会自动展开并使单元格变大。这是我实现可扩展单元的基本想法。 所以这是我用来获得所需结果的代码:
@objc func downArrowButtonClicked(_ sender: UIButton){
let indexPath = IndexPath(row: sender.tag, section: 0)
selectedIndex = indexPath
selectedCellIndex = sender.tag
isDescHidden = !isDescHidden
tableView.reloadRows(at: [indexPath], with: .automatic)
}
以上是单击单元格内按钮的代码。我想到了重新加载该特定索引的想法。我创建了一个名为 selectedCellIndex
的变量,我在 cellForRowAt
方法中使用它来进行一些更改。
我还在 viewDidLayoutSubviews() 中实现了一些代码,因为当我第一次单击单元格时没有完全展开。以防万一:
override func viewDidLayoutSubviews() {
super.viewDidLayoutSubviews()
let indexPath = selectedIndex
tableView.reloadRows(at: [indexPath ?? IndexPath(row: 0, section: 0)], with: .automatic)
}
并在 willDisplay
方法中调用它,最终解决了单元格扩展问题:
func tableView(_ tableView: UITableView, willDisplay cell: UITableViewCell, forRowAt indexPath: IndexPath) {
viewDidLayoutSubviews()
}
这是我的 cellForRowAt
函数:
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "CustomTableViewCell", for: indexPath) as! CustomTableViewCell
if indexPath.row == 0 {
cell.lblTitle.text = "Title 1"
cell.lblDesc.text = "Desc 1"
}
else if indexPath.row == 1 {
cell.lblTitle.text = "Title 2"
cell.lblDesc.text = "Desc 2"
}
else {
cell.lblTitle.text = "Title 3"
cell.lblDesc.text = "Desc 3"
}
if selectedCellIndex != nil {
if isDescHidden == false {
if cell.isDescHidden == true {
cell.lblDesc.isHidden = false
cell.btnArrow.setImage(UIImage(systemName: "chevron.up"), for: .normal)
}
else {
cell.lblDesc.isHidden = true
cell.btnArrow.setImage(UIImage(systemName: "chevron.down"), for: .normal)
}
}
else {
if cell.isDescHidden == true {
cell.lblDesc.isHidden = true
cell.btnArrow.setImage(UIImage(systemName: "chevron.down"), for: .normal)
}
else {
cell.lblDesc.isHidden = false
cell.btnArrow.setImage(UIImage(systemName: "chevron.up"), for: .normal)
}
}
cell.isDescHidden = !cell.isDescHidden
}
cell.btnArrow.tag = indexPath.row
cell.btnArrow.addTarget(self, action: #selector(downArrowButtonClicked(_:)), for: .touchUpInside)
return cell
}
从上面的代码可以看出,这种方法太混乱了。 isDescHidden
变量在主视图控制器和 table 视图单元格 class 中都有定义,我试图同时使用它们来展开或折叠特定的单元格。但是第一次它工作但如果我有 3 个单元格展开,折叠按钮单击不起作用 1-2 单击然后工作。
对于这种问题有更好的方法吗?或者有什么方法可以直接从 @objc func downArrowButtonClicked(_ sender: UIButton)
函数设置 cell.isDescHidden
值?所以我可以在 cellForRowAt
函数中使用它吗?
如果我可以直接从中更改单元格变量,我会很高兴。
使用以下函数自动设置行高,并为您的 stackView
top
和 bottom
约束
func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
return UITableView.automaticDimension
}
这是我的 CustomCell
class CustomCell: UITableViewCell {
@IBOutlet weak var titleCell: UILabel!
@IBOutlet weak var detail: UILabel!
@IBOutlet weak var arrowButton: UIButton!
let upArrow = UIImage(systemName: "chevron.up.circle.fill")
let downArrow = UIImage(systemName: "chevron.down.circle.fill")
var onArrowClick: ((UIButton)->())!
@IBAction func handleArrowButton(sender: UIButton){
onArrowClick(sender)
}
func updateArrowImage(expandStatus: Bool){
arrowButton.setImage(expandStatus ? downArrow : upArrow, for: .normal)
}
}
示例数据
let data = [
["Nothing", "description is very long description is very long description is very long description is very "],
["Nothing", "description is very long "],
["Nothing", "description is very long "],
["Nothing", "description is very long "],
["Nothing", "description is very long "]
]
var eachCellStatus: [Bool] = []
@IBOutlet weak var tableView: UITableView!
override func viewDidLoad() {
super.viewDidLoad()
tableView.dataSource = self
tableView.delegate = self
for _ in data {
eachCellStatus.append(true)
}
}
TableView 方法是这样的
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return data.count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "cell") as! CustomCell
cell.titleCell.text = data[indexPath.row][0]
cell.detail.text = data[indexPath.row][1]
cell.detail.isHidden = eachCellStatus[indexPath.row]
cell.updateArrowImage(expandStatus: self.eachCellStatus[indexPath.row])
cell.onArrowClick = { button in
self.eachCellStatus[indexPath.row].toggle()
cell.updateArrowImage(expandStatus: self.eachCellStatus[indexPath.row])
tableView.reloadRows(at: [indexPath], with: .automatic)
}
return cell
}
首先创建一个模型来将数据显示到单元格中。你必须保留细胞的状态。
struct CellData {
var title: String
var details: String
var isExpanded: Bool
}
在 CustomTableViewCell
中为 cellData 添加一个 属性 并从中分配 Outlet
s 数据。同时创建一个 protocol
以从 UIViewController
row
protocol CustomTableViewCellDelegate {
func reloadRow(sender: CustomTableViewCell, flag: Bool)
}
class CustomTableViewCell: UITableViewCell {
@IBOutlet weak var titleLabel: UILabel!
@IBOutlet weak var detailsLabel: UILabel!
@IBOutlet weak var showButton: UIButton!
var indexPath: IndexPath?
var delegate: CustomTableViewCellDelegate?
var data: CellData? {
didSet {
if let data = data {
if data.isExpanded == false {
detailsLabel.isHidden = true
showButton.setImage(UIImage(systemName: "chevron.down"), for: .normal)
}else {
detailsLabel.isHidden = true
showButton.setImage(UIImage(systemName: "chevron.up"), for: .normal)
}
titleLabel.text = data.title
detailsLabel.text = data.details
}
}
}
override func awakeFromNib() {
super.awakeFromNib()
titleLabel.text = nil
detailsLabel.text = nil
}
@IBAction func showButtonAction(_ sender: UIButton) {
if var data = data {
data.isExpanded.toggle()
delegate?.reloadRow(cell: self, flag: data.isExpanded)
}
}
}
在UIViewController
中添加一个CellData
类型的数组。您可以在 viewDidLoad()
方法中分配它的数据。
var tableData: [CellData]
修改 numberOfRowsInSection()
和 cellForRow()
方法,如 bleow。
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return tableData.count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "CustomTableViewCell", for: indexPath) as! CustomTableViewCell
cell.data = tableData[indexPath.row]
cell.delegate = self
return cell
}
func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
return UITableView.automaticDimension
}
然后确认 CustomTableViewCellDelegate
协议到 UIViewController
extension ViewController: CustomTableViewCellDelegate {
func reloadRow(sender: CustomTableViewCell, isExpanded: Bool) {
guard let tappedIndexPath = tableView.indexPath(for: sender) else { return }
tableData[tappedIndexPath.row].isExpanded = isExpanded
tableView.reloadRows(at: [indexPath], with: UITableView.RowAnimation.automatic)
}
}