自定义 UITableView 重新排序
Posted
技术标签:
【中文标题】自定义 UITableView 重新排序【英文标题】:Custom UITableView reorder 【发布时间】:2010-10-25 00:24:38 【问题描述】:我想知道是否有人有一个好的教程的链接,或者可以指出我正确的方向,以便在 Epic Win App 等 UITableView 中重新创建“拖动以重新排序”单元格。基本想法是您点击并按住列表项,然后拖动到您希望该项目所在的位置。任何帮助将不胜感激。
【问题讨论】:
如何实现这一点,如果我们有多个部分,每个部分有一行????请帮帮我! 【参考方案1】:使用内置方法的最简单方法如下:
首先,将表格单元格设置为启用显示重新排序控制。最简单的例子(使用 ARC):
这是假设 NSMutableArray *things
已在此类的其他位置创建
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
UITableViewCell *cell = [self.tableView dequeueReusableCellWithIdentifier:@"do not leak me"];
if (!cell)
cell = [[UITableViewCell alloc] init];
cell.showsReorderControl = YES;
cell.textLabel.text = [things objectAtIndex:indexPath.row];
return cell;
实现您的两个UITableViewDelegate
方法,如下所示:
这个方法告诉tableView允许重新排序
-(BOOL)tableView:(UITableView *)tableView canMoveRowAtIndexPath:(NSIndexPath *)indexPath
return YES;
这是 tableView 重新排序实际发生的地方
-(void)tableView:(UITableView *)tableView moveRowAtIndexPath:(NSIndexPath *)sourceIndexPath toIndexPath:(NSIndexPath *)destinationIndexPath
id thing = [things objectAtIndex:sourceIndexPath.row];
[things removeObjectAtIndex:sourceIndexPath.row];
[things insertObject:thing atIndex:destinationIndexPath.row];
然后不知何故,在某个地方,将编辑设置为真。这是您如何执行此操作的一个示例。 tableView 必须处于编辑模式才能重新排序。
- (IBAction)doSomething:(id)sender
self.table.editing = YES;
希望作为一个具体的例子。
【讨论】:
该问题明确指出要提供自定义重新排序选项,而不是默认选项。 @Unome 否。OP 选择了已接受的答案,这基本上是我答案的更摘要版本。谢谢。 像你说的那样接受的答案是问题要求的淡化版本。我已经发布了 UITableView 的工作子类。 我很抱歉。回想起来,我的cmets很粗鲁。我很沮丧,因为答案没有为我作为用户寻找的内容提供帮助。您的问题写得很仔细,写得很好,并提供了一个很好的答案,尽管不是我想要的答案。 +1【参考方案2】:这很简单——这可能就是为什么没有关于这个问题的明确教程的原因。
正常创建UITableView即可,但是将每个单元格的showsReorderControl
设置为TRUE。当您进入编辑模式时(通常通过按下“编辑”按钮并将 UITableView 的“编辑”值设置为 TRUE) - 重新排序栏将出现在单元格中。
注意:
如果您的数据源实现 tableView:canMoveRowAtIndexPath:
- 并且它返回“NO” - 重新排序栏将不会出现。
您还需要在数据源委托中实现–tableView:moveRowAtIndexPath:toIndexPath:
。
【讨论】:
我想做的一件事就是取代按钮并使整个单元格成为按钮。因此,您只需拖动单元格即可。你知道怎么做吗?还是如何做到这一点的垫脚石? 将 UITableCellView 子类化为您想要的任何东西都非常容易 - 因此只需使用您自己的重新排序栏按钮/区域来制作您的子类。 您是否能够按照 Brad 的建议重新连接栏/按钮区域?据我所见,拦截或调整重新排序按钮区域的大小绝非易事。看起来您可以在这里使用 Apple 的整个方法,或者完全从头开始重新排序。 我同意 Thomson 的观点,这远不是一个简单的问题,而且比使用几个 tableView 委托方法和编写子类要深入得多。如果您声称某事很容易,请提供证明它很容易的证据。【参考方案3】:此解决方案的功能类似于 OSX 上的提醒应用程序,它允许您通过按住并拖动任意位置来重新排列单元格。
我创建了一个 UITableView 的子类,它允许您拖动和重新排序单元格,而无需打开 editing
或使用标准的重新排序句柄。
基本的想法是我使用触摸开始和触摸结束来获取点击了哪个单元格,然后我创建了一个假视图,它实际上只是您点击的视图的屏幕截图,并来回移动它,交换单元格的背景。当用户放手时,我会取消隐藏原始视图。
class ReorderTableView: UITableView
var customView:UIImageView?
var oldIndexPath:NSIndexPath?
override func touchesBegan(touches: Set<UITouch>, withEvent event: UIEvent?)
guard let touch1 = touches.first else
return
oldIndexPath = self.indexPathForRowAtPoint(touch1.locationInView(self))
guard (oldIndexPath != nil) else
return
let oldCell = self.cellForRowAtIndexPath(self.oldIndexPath!)
customView = UIImageView(frame: CGRectMake(0, touch1.locationInView(self).y - 20, self.frame.width, 40))
customView?.image = screenShotView(oldCell!)
customView?.layer.shadowColor = UIColor.blackColor().CGColor
customView?.layer.shadowOpacity = 0.5
customView?.layer.shadowOffset = CGSizeMake(1, 1)
self.addSubview(customView!)
oldCell?.alpha = 0
override func touchesMoved(touches: Set<UITouch>, withEvent event: UIEvent?)
guard let touch1 = touches.first else
return
let newIndexPath = self.indexPathForRowAtPoint(touch1.locationInView(self))
guard newIndexPath != nil else
return
guard oldIndexPath != nil else
return
if newIndexPath != oldIndexPath
self.moveRowAtIndexPath(oldIndexPath!, toIndexPath: newIndexPath!)
oldIndexPath = newIndexPath
self.cellForRowAtIndexPath(self.oldIndexPath!)!.alpha = 0
self.customView!.frame.origin = CGPointMake(0, touch1.locationInView(self).y - 20)
override func touchesEnded(touches: Set<UITouch>, withEvent event: UIEvent?)
self.customView?.removeFromSuperview()
self.customView = nil
guard (oldIndexPath != nil) else
return
self.cellForRowAtIndexPath(self.oldIndexPath!)!.alpha = 1
func screenShotView(view: UIView) -> UIImage?
let rect = view.bounds
UIGraphicsBeginImageContextWithOptions(rect.size,true,0.0)
let context = UIGraphicsGetCurrentContext()
CGContextTranslateCTM(context, 0, -view.frame.origin.y);
self.layer.renderInContext(context!)
let capturedImage = UIGraphicsGetImageFromCurrentImageContext()
UIGraphicsEndImageContext()
return capturedImage
最后,您可以重新排序单元格,而无需使用句柄。这可以针对不同的手势或模式进行扩展,具体取决于用例,但我将其保留为香草版本。如果您有任何问题,请告诉我。
更新:
我发现了一些注意事项。弄清楚如何使用滚动并相应地修改它是非常重要的。例如,当我模拟它时,我设置了scrollingEnabled = false.
从长远来看,我确实想要滚动,所以我将代码更改为仅在超过 0.25 的压力机上运行此功能(我使用了一些计时器来执行此操作)。然后我会在此期间暂时禁用滚动,并在完成后重新启用。
【讨论】:
是什么让你认为 OP 想要这个?接受的答案使用句柄。谢谢。 他的问题:“基本的想法是你点击并按住一个列表项,然后你拖动到你想要的项目”没有指定他想使用句柄,并且标题“自定义重新排序”意味着不使用默认方法。我有一个类似的问题,这里的答案都没有帮助我。我试图提供一个答案,以帮助那些有类似问题的人。接受的答案不等于正确答案。谢谢。 一切都好。如果您想添加另一个答案,以显示另一种完美的方法。无需围绕其他答案来宣传您的 +1 我明白,我的 cmets 是在尝试回答问题之前制作的,我的意图绝不是宣传我的答案。 一切都好。那么这个答案中的20
之类的硬编码数字是什么?以上是关于自定义 UITableView 重新排序的主要内容,如果未能解决你的问题,请参考以下文章
重新排序单元格后重新加载自定义 UITableViewCell