我有一个非常有趣的案例,其中我有两个UITableViews
。主要TableView
是UITableViewController
。每个单元由三部分组成。 Header
显示标题,Body
在您选择cell
时充当手风琴,最后是UITableView
使用自定义Cell Identifier
但使用与UITableViewController
或parent
相同的代理。
现在我遇到的问题是,当用户滚动时,所有标题都会混淆parent uitableview
以及child uitableview
,我知道它与我的dequeueReusableCellWithIdentifier
有关{1}}。
单词developer
的位置,即父tableview
。混乱的文字that is a sub uitableview
。我正在寻找一些关于解决这个问题的最佳解决方案的指导。这就是我在做的事情:
override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
if tableView == self.tableView {
// # Adjust profile picture
//cell.headerView.profileImage.frame = CGRectMake(0,0, 50, 50)
cell.headerView.profileImage.image = UIImage(named: "avatar-ph.jpg")
cell.headerView.profileImage.layer.cornerRadius =
cell.headerView.profileImage.frame.size.width / 2
cell.headerView.profileImage.clipsToBounds = true
... do stuff
cell.detailView.innertableView.dataSource = self
// This is needed for dequeueing to succeed:
cell.detailView.innertableView.registerClass(SingleOrderTableViewCell.self, forCellReuseIdentifier: "SingleOrderTableViewCell");
cell.detailView.innertableView.reloadData()
}
else {
// [B] INNER TABLE VIEW
let cell = tableView.dequeueReusableCellWithIdentifier("SingleOrderTableViewCell", forIndexPath: indexPath) as! SingleOrderTableViewCell
// # Setup our data to display
// ## Title
cell.title = UITextField (frame:CGRectMake(75, 5, 300, 20));
cell.title.font = UIFont(name: "System Light", size: 10);
cell.title.text = drinkName;
cell.title.textColor = UIColor(netHex:0x362C6B);
// ## qty
cell.qty = UITextField (frame:CGRectMake(75, 22.5, 300, 20));
cell.qty.font = UIFont(name: "System Light", size: 10);
cell.qty.text = "Qty: " + qty;
cell.qty.textColor = UIColor.grayColor();
// # Add to subframe
cell.addSubview(cell.title);
cell.addSubview(cell.qty);
return cell
}
}
上面的代码显示了我如何处理两个tableviews
的区别并将相应的单元格设置为正确的tableview
。
现在需要注意的是,此处填充的信息基于从服务器返回的对象。所以我的想法是,它工作正常;但indexPath.row
与实际关联的cell
相关。
有任何想法或建议吗?
答案 0 :(得分:1)
有几点意见:
您使用dequeueReusableCellWithIdentifier(indexPath:)
对单元格进行了排队,但您要在cellForRowAtIndexPath
中添加子视图。不幸的是,这意味着当重新使用一个单元格时,每次都会添加一个新标签。
如果您要使用这种以编程方式创建的单元格的方法,则应将子视图添加到UITableViewCell
子类“init
或awakeFromNIB
方法中。这些方法只调用一次,当单元格重用于表格中的另一行时,不会再调用这些方法。
我可能会建议进一步简化这一点,切断Gordian结,而不是以编程方式创建单元格。相反,您可以在故事板中添加原型单元格,然后您根本不需要自己调用addSubview
。使用单元原型的过程如下:
创建空白UITableViewCell
子类。
将单元格原型添加到tableview单元格中。您可以通过将“表视图单元”从Interface Builder对象库拖到表视图中来完成此操作。 (一般来说,它会为您提供一个单元原型,但您不必这样做。)
在Interface Builder的“Identity Inspector”面板上将单元原型的基类设置为您的UITableViewCell
子类。还要在“Attributes Inspector”面板上为该原型单元格提供唯一的故事板标识符。
在设计时在Interface Builder中拖动您想要的任何控件,而不是在运行时以编程方式拖动。
将您在Interface Builder中添加的控件的IBOutlet
引用添加到自定义UITableViewCell
子类中。
如果您有两种不同类型的细胞,请为每种细胞重复此过程。
与原始问题无关,而不是在tableview中进行tableview,我建议创建一个包含两个单元格原型的单个tableview,一个用于标题单元格,另一个用于详细单元格。
然后,您可以在表格视图中为每个可折叠单元格组创建单独的“部分”。然后numberOfRowsInSection
将根据组是否折叠确定有多少行。如果它已折叠,只需返回标题单元格1
即可。如果它没有折叠,请返回1
加上该部分中的详细信息行数。
因此,当您想要隐藏行时,请更新模型中的某个标志以反映该部分已折叠,然后使用适当的动画调用deleteRowsAtIndexPaths
以隐藏行。或者,当您想要显示行时,再次更新模型,然后调用addRowsAtIndexPaths
。
例如,请考虑以下事项:
struct Comedian {
let name: String
}
struct Troupe {
let name: String
let items: [Comedian]
var collapsed = false
}
class ViewController: UITableViewController {
var comedyTroupes = [
Troupe(name: "The Three Stooges", collapsed: true, items: [
Comedian(name: "Mo"),
Comedian(name: "Larry"),
Comedian(name: "Curly")]
),
Troupe(name: "The Marx Brothers", collapsed: true, items: [
Comedian(name: "Chico"),
Comedian(name: "Harpo"),
Comedian(name: "Groucho"),
Comedian(name: "Gummo"),
Comedian(name: "Zeppo")]
),
Troupe(name: "The Smothers Brothers", collapsed: true, items: [
Comedian(name: "Richard"),
Comedian(name: "Thomas")]
),
Troupe(name: "Laurel and Hardy", collapsed: true, items: [
Comedian(name: "Laurel"),
Comedian(name: "Hardy")]
),
Troupe(name: "Abbott and Costello", collapsed: true, items: [
Comedian(name: "Abbott"),
Comedian(name: "Costello")]
),
]
override func numberOfSectionsInTableView(tableView: UITableView) -> Int {
return comedyTroupes.count
}
// if the section is collapsed, we only have the header cell; otherwise we have header cell and detail cells
override func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return comedyTroupes[section].collapsed ? 1 : comedyTroupes[section].items.count + 1
}
// row 0 will be the name of the comedy troupe; the rest of the rows will be the names of the comedians
override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
if indexPath.row == 0 {
let cell = tableView.dequeueReusableCellWithIdentifier("HeaderCell", forIndexPath: indexPath) as! HeaderCell
cell.comedyTroupeLabel.text = comedyTroupes[indexPath.section].name
return cell
} else {
let cell = tableView.dequeueReusableCellWithIdentifier("DetailCell", forIndexPath: indexPath) as! DetailCell
cell.comedianNameLabel.text = comedyTroupes[indexPath.section].items[indexPath.row - 1].name
return cell
}
}
// if we select header row, update model and then either call
// `addRowsAtIndexPaths or `deleteRowsAtIndexPaths` as appropriate.
override func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) {
if indexPath.row == 0 {
let collapsed = !comedyTroupes[indexPath.section].collapsed
comedyTroupes[indexPath.section].collapsed = collapsed
let indexPaths = Array(1 ... comedyTroupes[indexPath.section].items.count).map { NSIndexPath(forRow: $0, inSection: indexPath.section) }
if collapsed {
tableView.deleteRowsAtIndexPaths(indexPaths, withRowAnimation: .Middle)
} else {
tableView.insertRowsAtIndexPaths(indexPaths, withRowAnimation: .Middle)
}
} else {
// do whatever you want if user selects one of the detail cells
}
}
}
产量:
现在,每当选择标题行时,我都会折叠并展开详细信息行,但您可以使用所需的任何UI(例如,您可以在标题行单元格上添加一些按钮以打开详细信息行和关闭)。此外,如果你不喜欢这个“额外的标题行”模型,你也可以使用正确的节标题视图(但是你必须跳过箍以将标题视图添加到表视图中,捕获它的点击次数等) 。我认为这个标题单元格和细节单元格方法最简单,尽管不是那么直观。但是,无论如何,我希望这说明你不需要在tableviews中使用tableviews。