我有带有部分和行(https://imgur.com/a/hrYTEVR)的UITableView。我知道如何启用对行的重新排序,但是我不知道如何实现对部分的重新排序。 我需要将重排序控件添加到section(https://imgur.com/a/V5kU9Ew)中,然后当用户触摸此控件时,section下的行应该失败。之后,用户可以将部分移到新位置。 在阅读了关于stackoverflow和其他站点的主题之后,我没有发现如何实现这样的好主意。 我考虑过通过单元实现节,但是在这种情况下,我无法在节下翻转行以进一步移动到新位置。 如果您有任何想法,请给我建议。谢谢!
答案 0 :(得分:0)
您可以将标题用于节,而不能将表格视图单元格用于节。首先,您需要告诉表视图中需要多少节:
func numberOfSections(in tableView: UITableView) -> Int{
return yourSectionNumber
}
然后为每个部分指定:
func headerView(forSection section: Int) -> UITableViewHeaderFooterView? {
return yourSpecifiedHeaderView
}
或者,如果要使用Apple提供的部分的默认标题视图,则可以使用:
func tableView(_ tableView: UITableView, titleForHeaderInSection section: Int) -> String? {
return yourSectionTitle
}
然后进行订购,您可以一起订购您的部分和数据。这里的建议是创建自己的包含tableView行数据的类。例如:
class Foo {
var sectionTitle: String
var data: [AnotherClassForData]
}
class AnotherClassForData {
var rowTitle: String
// other properties
}
然后在tableView中,您将有一个类为Foo
的对象的数组。
例如:
var dataSource = [Foo]()
func tableView(_ tableView: UITableView, titleForHeaderInSection section: Int) -> String? {
return dataSource[section].sectionTitle
}
然后在代码中的某个地方,您可以像这样重新排序:
dataSource.sorted(by: { $0.sectionTitle > $1.sectionTitle } )
然后,您可以像往常一样重新加载tableView:
DispatchQueue.main.async {
self.tableView.reloadData()
}
答案 1 :(得分:0)
没有本机功能可以实现您想要的。如果我理解正确,那么您将希望折叠整个行的一部分,然后开始拖动“标题”。如果您想自己执行此操作,建议您从平移手势识别器开始,该识别器在标题按钮上触发。
手势应该相对明显。在标题上启动后,您需要在表格视图中使用locationIn
来跟踪位置。
要折叠行,您需要做的就是使用适当的动画修改表格视图单元格,例如:
tableView.beginUpdates()
tableView.deleteSections([myIndexPath], with: .top) // Maybe experiment with animation type
// Modify whatever you need to correspond this change in the data source
tableView.endUpdates()
由于将要删除的部分也将删除具有手势识别器的视图(标题)。这意味着将手势直接添加到表视图甚至是其超级视图可能会更好。您仅在按下标题上的那些按钮之一时才需要强制它触发。您可以对此有了一些认识here。其余不受此更改的影响。
在这一点上,您可能需要创建一个额外的视图,该视图代表您的部分堆栈并顺您的手指。如果您将其添加为子视图并在其超级视图中使用平移手势识别器locationIn
来操纵它的中心,这应该非常容易:
movableSectionView.center = panGestureRecognizer.location(in: movableSectionView.superview!)
因此,到目前为止,您应该能够抓住一个折叠所有单元格的区域,并能够拖动“部分堆栈”视图。现在,您需要检查表格视图中的什么位置,以了解将节放在哪里。这有点痛苦,但是可以使用visibleCells
和tableView.indexPath(for: )
来完成:
func indexPathForGestureRecognizer(_ recognizer: UIGestureRecognizer) -> IndexPath {
let coordinateView: UIView = tableView.superview! // This can actually be pretty much anything as long as it is in hierarchy
let y = recognizer.location(in: coordinateView).y
if let hitCell = tableView.visibleCells.first(where: { cell in
let frameInCoordinateView = cell.convert(cell.bounds, to: coordinateView)
return frameInCoordinateView.minY >= y && frameInCoordinateView.maxY <= y
}) {
// We have the cell at which the finger is. Retrieve the index path
return tableView.indexPath(for: hitCell) ?? IndexPath(row: 0, section: 0) // This should always succeed but just in case
} else {
// We may be out of bounds. That may be either too high which means above the table view otherwise too low
if recognizer.location(in: tableView).y < 0.0 {
return IndexPath(row: 0, section: 0)
} else {
guard tableView.numberOfSections > 0 else {
return IndexPath(row: 0, section: 0) // Nothing in the table view at all
}
let section = tableView.numberOfSections-1
return IndexPath(row: tableView.numberOfRows(inSection: section), section: section)
}
}
}
手势识别器结束后,您可以使用此方法来获取要放入项目的部分。因此:
tableView.beginUpdates()
// Modify whatever you need to correspond this change in the data source
tableView.insertSections([indexPathForGestureRecognizer(panGestureRecognizer).section], with: .bottom)
tableView.endUpdates()
基本上,这对于重新排序应该足够了,但是您可能希望在表格视图中显示拖动部分所在的位置。就像在要放入堆栈的部分末尾有一个占位符。通过简单地添加然后移动一个额外的占位符单元格(重用indexPathForGestureRecognizer
来获得位置),这应该相对容易。
玩得开心。