带有 UITableView 的 UISegmentControl - UITableViewCell 布局在更改段时保持不变
UISegmentControl with UITableView - UITableViewCell layout remains same on changing the segment
在问题标题中提到的场景中,在更改段时,理想情况下 UITableView
应该重新加载,因此 UITableViewCell
也应该重新加载。问题是,所有内容都会像标签文本一样更新。但是,如果我在一个段中扩展了单元格的子视图,则在更改段后它仍然保持扩展状态。
段索引更改函数:
@IBAction func segmentOnChange(sender: UISegmentControl)
{
// Few lines
// self.tableMenu.reloadData()
}
屏幕截图 1 :
截图 2 :
理想情况下,在屏幕截图 2 中,购物车视图应该已折叠。
更新:
Show/Hide 视图:
func showHideCartView(sender: UIButton)
{
let cell = self.tableMenu.cellForRow(at: IndexPath(row: 0, section: Int(sender.accessibilityHint!)!)) as! RestaurantMenuItemCell
if sender.tag == 1
{
// Show cart view
cell.buttonArrow.tag = 2
cell.viewAddToCart.isHidden = false
cell.constraint_Height_viewAddToCart.constant = 50
cell.buttonArrow.setImage(UIImage(named: "arrowUp.png"), for: .normal)
}
else
{
// Show cart view
cell.buttonArrow.tag = 1
cell.viewAddToCart.isHidden = true
cell.constraint_Height_viewAddToCart.constant = 0
cell.buttonArrow.setImage(UIImage(named: "arrowDown.png"), for: .normal)
}
self.tableMenu.reloadData()
}
cellForRowAtIndexPath :
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "RestaurantMenuItemCell", for: indexPath) as! RestaurantMenuItemCell
cell.selectionStyle = .none
let menuItem = self.menuItems[indexPath.section]
cell.imageViewMenuItem.image = UIImage(named: "recommend0@2x.png")
cell.labelName.text = menuItem.name
cell.labelDescription.text = menuItem.description
cell.labelPrice.text = String(format: "$%i", menuItem.price!)
cell.buttonArrow.accessibilityHint = String(format: "%i", indexPath.section)
cell.buttonArrow.addTarget(self, action: #selector(self.showHideCartView(sender:)), for: .touchUpInside)
return cell
}
这里发生了什么,当您单击任何行时,它将根据 showHideCartView
方法中的第一个条件为真展开,之后当您更改保持前一行高度不变的段索引时因为你正在重用单元格所以你必须在更改段索引时设置每一行的正常高度。
对于 indexPath
的对象,如
var selectedIndexPath: NSIndexPath?
然后在showHideCartView
方法中设置selectedIndexPath
func showHideCartView(sender: UIButton) {
selectedIndexPath = NSIndexPath(row: 0, section: Int(sender.accessibilityHint!)!)) // you can change row and section as per your requirement.
//// Your other code
}
然后在您更改段索引时应用以下逻辑。
@IBAction func segmentOnChange(sender: UISegmentControl)
{
if indexPath = selectedIndexPath { // check selectedIndexPath is not nil
let cell = self.tableMenu.cellForRow(at: indexPath) as! RestaurantMenuItemCell
cell.buttonArrow.tag = 1
cell.viewAddToCart.isHidden = true
cell.constraint_Height_viewAddToCart.constant = 0
cell.buttonArrow.setImage(UIImage(named: "arrowDown.png"), for: .normal)
}
selectedIndexPath = nil // assign nil to selectedIndexPath
// Few lines
self.tableMenu.reloadData() // Reload your tableview
}
由于您依靠发件人按钮的标签来确定单元格是否应以展开或折叠状态显示,因此您需要确保当段更改时,所有单元格的标签'buttonArrow
也改为 1.
除非发生这种情况,否则单元格将被重复使用,并且由于 buttonArrow
的标签设置为 2,它将显示为已展开。
您正在重复使用单元格,请参阅 cellForRowAt
实施的第一行:
let cell = tableView.dequeueReusableCell(withIdentifier: "RestaurantMenuItemCell", for: indexPath) as! RestaurantMenuItemCell
这意味着 tableView 不会创建新单元格,也不会重绘它,除非给定 indexPath
有必要。但是,在代码中,您通过在单元格的子视图上设置一些高度限制和 isHidden
标志来扩展单元格。现在,一旦您在新段重新加载 table,tableView
将使用已渲染的单元格使重新加载尽可能高效。然而,这意味着,尽管您将更改单元格中的数据,除非您明确折叠它,否则它将保持展开状态(因为之前您已将约束设置为展开高度)。
更改段时需要重置展开状态。现在让我们详细说明,因为我相信您当前的解决方案中有一个隐藏的错误:
首先,正如我所说,您正在使单元格出列,以防万一 table 中有很多项目并且您正在滚动浏览它们,展开的单元格很有可能甚至稍后在 table 视图中的某个地方也会被重用。所以看起来也有一些随机项目扩展了。
因此,我建议您提供一些模型来记住应该扩展哪些单元格,然后使用此模型中的信息更新每个单元格的状态,然后再 return 在您的 [=11] 中更新每个单元格的状态=].例如,该模型可以是一个简单的整数值数组,表示展开的单元格的索引 - 例如,如果数组中有索引 3,则意味着应该展开第 3 行的单元格。然后,当您在 cellForRowAt
中为 indexPath
行 = 3 的单元格出列时,您应该在 returning 之前对该单元格设置约束。这样你就可以删除我提到的错误。此外,当您更改段时,您可以从数组中删除所有索引以表示不应再扩展任何单元格(在调用 tableView.reloadData()
之前执行)。
在问题标题中提到的场景中,在更改段时,理想情况下 UITableView
应该重新加载,因此 UITableViewCell
也应该重新加载。问题是,所有内容都会像标签文本一样更新。但是,如果我在一个段中扩展了单元格的子视图,则在更改段后它仍然保持扩展状态。
段索引更改函数:
@IBAction func segmentOnChange(sender: UISegmentControl)
{
// Few lines
// self.tableMenu.reloadData()
}
屏幕截图 1 :
截图 2 :
理想情况下,在屏幕截图 2 中,购物车视图应该已折叠。
更新:
Show/Hide 视图:
func showHideCartView(sender: UIButton)
{
let cell = self.tableMenu.cellForRow(at: IndexPath(row: 0, section: Int(sender.accessibilityHint!)!)) as! RestaurantMenuItemCell
if sender.tag == 1
{
// Show cart view
cell.buttonArrow.tag = 2
cell.viewAddToCart.isHidden = false
cell.constraint_Height_viewAddToCart.constant = 50
cell.buttonArrow.setImage(UIImage(named: "arrowUp.png"), for: .normal)
}
else
{
// Show cart view
cell.buttonArrow.tag = 1
cell.viewAddToCart.isHidden = true
cell.constraint_Height_viewAddToCart.constant = 0
cell.buttonArrow.setImage(UIImage(named: "arrowDown.png"), for: .normal)
}
self.tableMenu.reloadData()
}
cellForRowAtIndexPath :
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "RestaurantMenuItemCell", for: indexPath) as! RestaurantMenuItemCell
cell.selectionStyle = .none
let menuItem = self.menuItems[indexPath.section]
cell.imageViewMenuItem.image = UIImage(named: "recommend0@2x.png")
cell.labelName.text = menuItem.name
cell.labelDescription.text = menuItem.description
cell.labelPrice.text = String(format: "$%i", menuItem.price!)
cell.buttonArrow.accessibilityHint = String(format: "%i", indexPath.section)
cell.buttonArrow.addTarget(self, action: #selector(self.showHideCartView(sender:)), for: .touchUpInside)
return cell
}
这里发生了什么,当您单击任何行时,它将根据 showHideCartView
方法中的第一个条件为真展开,之后当您更改保持前一行高度不变的段索引时因为你正在重用单元格所以你必须在更改段索引时设置每一行的正常高度。
对于 indexPath
的对象,如
var selectedIndexPath: NSIndexPath?
然后在showHideCartView
方法中设置selectedIndexPath
func showHideCartView(sender: UIButton) {
selectedIndexPath = NSIndexPath(row: 0, section: Int(sender.accessibilityHint!)!)) // you can change row and section as per your requirement.
//// Your other code
}
然后在您更改段索引时应用以下逻辑。
@IBAction func segmentOnChange(sender: UISegmentControl)
{
if indexPath = selectedIndexPath { // check selectedIndexPath is not nil
let cell = self.tableMenu.cellForRow(at: indexPath) as! RestaurantMenuItemCell
cell.buttonArrow.tag = 1
cell.viewAddToCart.isHidden = true
cell.constraint_Height_viewAddToCart.constant = 0
cell.buttonArrow.setImage(UIImage(named: "arrowDown.png"), for: .normal)
}
selectedIndexPath = nil // assign nil to selectedIndexPath
// Few lines
self.tableMenu.reloadData() // Reload your tableview
}
由于您依靠发件人按钮的标签来确定单元格是否应以展开或折叠状态显示,因此您需要确保当段更改时,所有单元格的标签'buttonArrow
也改为 1.
除非发生这种情况,否则单元格将被重复使用,并且由于 buttonArrow
的标签设置为 2,它将显示为已展开。
您正在重复使用单元格,请参阅 cellForRowAt
实施的第一行:
let cell = tableView.dequeueReusableCell(withIdentifier: "RestaurantMenuItemCell", for: indexPath) as! RestaurantMenuItemCell
这意味着 tableView 不会创建新单元格,也不会重绘它,除非给定 indexPath
有必要。但是,在代码中,您通过在单元格的子视图上设置一些高度限制和 isHidden
标志来扩展单元格。现在,一旦您在新段重新加载 table,tableView
将使用已渲染的单元格使重新加载尽可能高效。然而,这意味着,尽管您将更改单元格中的数据,除非您明确折叠它,否则它将保持展开状态(因为之前您已将约束设置为展开高度)。
更改段时需要重置展开状态。现在让我们详细说明,因为我相信您当前的解决方案中有一个隐藏的错误:
首先,正如我所说,您正在使单元格出列,以防万一 table 中有很多项目并且您正在滚动浏览它们,展开的单元格很有可能甚至稍后在 table 视图中的某个地方也会被重用。所以看起来也有一些随机项目扩展了。
因此,我建议您提供一些模型来记住应该扩展哪些单元格,然后使用此模型中的信息更新每个单元格的状态,然后再 return 在您的 [=11] 中更新每个单元格的状态=].例如,该模型可以是一个简单的整数值数组,表示展开的单元格的索引 - 例如,如果数组中有索引 3,则意味着应该展开第 3 行的单元格。然后,当您在 cellForRowAt
中为 indexPath
行 = 3 的单元格出列时,您应该在 returning 之前对该单元格设置约束。这样你就可以删除我提到的错误。此外,当您更改段时,您可以从数组中删除所有索引以表示不应再扩展任何单元格(在调用 tableView.reloadData()
之前执行)。