Iphone 自定义UITableView重新排序

Iphone 自定义UITableView重新排序,iphone,cocoa-touch,uitableview,uikit,Iphone,Cocoa Touch,Uitableview,Uikit,我想知道是否有人可以链接到一个好的教程,或者可以为我指出正确的方向,在像Epic Win应用程序这样的UITableView中重新创建“拖动以重新排序”单元格。其基本思想是点击并按住列表项,然后将其拖动到所需位置。任何帮助都将不胜感激。这是非常直截了当的-这可能就是为什么没有关于这一问题的明确教程的原因 只需正常创建UITableView,但将每个单元格的showsReorderControl设置为TRUE。当您进入编辑模式时(通常通过按下“编辑”按钮并将UITableView的“编辑”值设置为

我想知道是否有人可以链接到一个好的教程,或者可以为我指出正确的方向,在像Epic Win应用程序这样的UITableView中重新创建“拖动以重新排序”单元格。其基本思想是点击并按住列表项,然后将其拖动到所需位置。任何帮助都将不胜感激。

这是非常直截了当的-这可能就是为什么没有关于这一问题的明确教程的原因

只需正常创建UITableView,但将每个单元格的
showsReorderControl
设置为TRUE。当您进入编辑模式时(通常通过按下“编辑”按钮并将UITableView的“编辑”值设置为TRUE),重排序栏将显示在单元格中

注:

如果您的数据源实现了
tableView:canMoveRowAtIndexPath:
-并且返回“否”-则不会显示重新排序栏


您还需要在数据源委托中实现
–tableView:MoveRowatineXpath:toIndexPath:

使用内置方法的最简单方法如下:

首先,将表格单元格设置为启用“显示重新排序”控件。最简单的示例(使用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;
}

希望这可以作为一个具体的例子。

这个解决方案的功能类似于OSX上的提醒应用程序,它允许您通过按住并拖动任意位置来重新排序单元格

我已经创建了UITableView的一个子类,它允许您拖动单元格并对其重新排序,而无需启用
编辑或使用标准的重新排序句柄

基本的想法是我使用触摸开始和触摸结束来获得点击的单元格,然后我创建一个假视图,它实际上只是你点击的视图的屏幕截图,并来回移动,在背景中交换单元格。当用户放开时,我会取消隐藏原始视图

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
}

}
类ReorderTableView:UITableView{
var customView:UIImageView?
var oldIndexPath:nsindepath?
覆盖功能触摸开始(触摸:设置,withEvent事件:UIEvent?){
防护罩让接触1=首先接触{
返回
}
oldIndexPath=self.indexPathForRowAtPoint(touch1.locationInView(self))
守卫(oldIndexPath!=nil)其他{
返回
}
让oldCell=self.cellForRowAtIndexPath(self.oldIndexPath!)
customView=UIImageView(帧: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
}
覆盖功能触摸移动(触摸:设置,带事件:UIEvent?){
防护罩让接触1=首先接触{
返回
}
让newindexath=self.indexPathForRowAtPoint(touch1.locationInView(self))
guard newIndexPath!=无其他{
返回
}
守卫oldIndexPath!=无其他{
返回
}
如果newindepath!=oldIndexPath{
self.moveRowatineXpath(oldIndexPath!,toIndexPath:newIndexPath!)
oldIndexPath=newIndexPath
self.cellforrowatinedexpath(self.oldIndexPath!)!.alpha=0
}
self.customView!.frame.origin=CGPointMake(0,touch1.locationInView(self.y-20)
}
覆盖func touchesEnded(触摸:设置,withEvent事件:UIEvent?){
self.customView?.removeFromSuperview()
self.customView=nil
守卫(oldIndexPath!=nil)其他{
返回
}
self.cellforrowatinedexpath(self.oldIndexPath!)!.alpha=1
}
func屏幕快照视图(视图:UIView)->UIImage{
设rect=view.bounds
UIGraphicsBeginImageContextWithOptions(矩形大小,true,0.0)
let context=UIGraphicsGetCurrentContext()
CGContextTranslateCm(上下文,0,-view.frame.origin.y);
self.layer.renderInContext(context!)
让capturedImage=UIGraphicsGetImageFromCurrentImageContext()
UIGraphicsSendImageContext()
返回捕获图像
}
}
最后,您可以对单元格重新排序,而不必使用句柄。这可以扩展到不同的手势或模式,具体取决于用例,但我把它作为一个普通版本。如果你有任何问题,请告诉我

更新:


我发现了一些警告。弄清楚如何使用滚动并相应地修改它是非常重要的。例如,当我模拟它时,我设置了
scrollingEnabled=false。
从长远来看,我确实想要滚动,所以我更改了代码,使其仅在大于0.25的按键上运行此功能(我使用了一些计时器来执行此操作)。在此期间,我将暂时禁用滚动,并在完成后重新启用

我希望能做的一件事是取代按钮,让整个单元格成为按钮。这样你就可以拖动单元格了。你知道怎么做吗?或者是如何做到这一点的垫脚石?很容易将UITableCellView子类化为您想要的任何内容-因此,只需使用您自己的重新排序栏按钮/区域即可。您是否能够按照Brad的建议重新布线栏/按钮区域?就我所见,截取或调整“重新排序”按钮区域的大小绝非易事。我同意汤姆森的观点,这远远不是一个简单的问题,而且比使用几个tableView委托方法和编写子类要深入得多。如果你要一些