通过合并将项目从一个tableView移动到另一个tableView

时间:2011-11-25 10:31:52

标签: objective-c uitableview ipad

假设我在横向模式的ipad上有两个UITableViews。 现在我想将多个项目从一个tableView移动到另一个tableView。允许将它们插入另一个tableView的底部。两者都激活了multiSelection。

现在运动本身对正常细胞没有问题。但是在我的程序中,每个单元格都有一个包含单元格的consolidationState的对象。单元格可以有4种状态:Basic,Holding,Parent,Child。 基本=普通的细胞。 保持=包含多个孩子但在此状态下不会显示的单元格。 Parent =包含多个子项的单元格,直接显示在此单元格下方。 Child =父细胞创建的细胞。

每个单元格中的对象也有一些包含其子元素的数组。该对象还包含一个quantityValue,它显示在单元格本身上。

现在运动变得棘手。保持和父母细胞根本无法移动。基本细胞可以自由移动。子单元格可以自由移动,但是基于父级中剩余的子单元格数量。父母将一起更改或删除。 如果父单元格中有多个子单元格,则它将保留为父单元格。 否则父母没有或1个儿童细胞,并且没用。它将被删除。

移动的项目将始终处于相同的状态。它们都是基本细胞。

这是我编写动作的方式:

*首先,我确定哪个tableViews是发送者,哪个是接收者。

*其次我要求所有indexPathsForSelectedRows并将它们从最高行排序到最低行。

*然后我构建要传输的数据。我通过遍历selectedRows并从发件人的listOfItems询问他们的对象来做。

*当我保存所有需要的数据时,我会删除发件人TableView中的所有项目。这就是为什么我对selectedRows进行排序所以我可以从最高的indexPath.row开始并删除而不会搞砸其他indexPaths。

  • *当我遍历selectedRows时,我会检查是否找到了状态为Basic或Child的单元格。

  • *如果是基本单元格,我什么也不做,只删除单元格。 (这适用于所有基本单元格)

  • *如果它是一个子单元格,我会立即检查它的父单元格。由于所有子单元格都直接位于父单元格下方,而其他父级单元格不在其父级之下,因此我可以安全地获取所选子单元格的路径并向上移动并找到它的父单元格。当找到这个父单元格时(这将始终发生,没有例外),它必须相应地改变。

    • *将删除父单元格,或者内部对象的数量和子项将减少。
  • *父细胞相应更改后,子细胞被删除,类似于基本细胞

*在删除单元格之后,接收器tableView将构建新的indexPaths,因此movingObjects将有一个位置。

*然后我将对象插入接收器TableView的listOfItems。

代码的工作方式如下: 仅移动基本单元格。 移动基本单元格,并移动每个父项的1个子项。 移动单个基本/子单元格。

代码在以下情况下无法运作: 我选择了一个或多个父母单元的所有孩子。

问题发生在更新父单元格的某处。我现在盲目地盯着代码,所以也许新面貌会有助于解决问题。任何帮助将不胜感激。

以下是应该进行移动的方法:

-(void)moveSelectedItems
{ 
    UITableView *senderTableView = //retrieves the table with the data here.
    UITableView *receiverTableView = //retrieves the table which gets the data here.

    NSArray *selectedRows = senderTableView.indexPathsForSelectedRows;

    //sort selected rows from lowest indexPath.row to highest
    selectedRows = [selectedRows sortedArrayUsingSelector:@selector(compare:)];

    //build up target rows (all objects to be moved)
    NSMutableArray *targetRows = [[NSMutableArray alloc] init];
    for (int i = 0; i<selectedRows.count; i++) 
    {
        NSIndexPath *path = [selectedRows objectAtIndex:i];
        [targetRows addObject:[senderTableView.listOfItems objectAtIndex:path.row]];
    }

    //delete rows at active
    for (int i = selectedRows.count-1; i >= 0; i--) 
    {
        NSIndexPath *path = [selectedRows objectAtIndex:i];

        //check what item you are deleting. act upon the status. Parent- and HoldingCells cant be selected so only check for basic and childs
        MyCellObject *item = [senderTableView.listOfItems objectAtIndex:path.row];
        if (item.consolidatedState == ConsolidationTypeChild) 
        {
            for (int j = path.row; j >= 0; j--) 
            {
                MyCellObject *consolidatedItem = [senderTableView.listOfItems objectAtIndex:j];
                if (consolidatedItem.consolidatedState == ConsolidationTypeParent) 
                {
                    //copy the consolidated item but with 1 less quantity
                    MyCellObject *newItem = [consolidatedItem copyWithOneLessQuantity]; //creates a copy of the object with 1 less quantity.

                    if (newItem.quantity > 1)
                    {
                        newItem.consolidatedState = ConsolidationTypeParent;
                        [senderTableView.listOfItems replaceObjectAtIndex:j withObject:newItem];
                    }
                    else if (newItem.quantity == 1)
                    {
                        newItem.consolidatedState = ConsolidationTypeBasic;
                        [senderTableView.listOfItems removeObjectAtIndex:j];

                        MyCellObject *child = [senderTableView.listOfItems objectAtIndex:j+1];

                        child.consolidatedState = ConsolidationTypeBasic;

                        [senderTableView.listOfItems replaceObjectAtIndex:j+1 withObject:child];
                    }
                    else 
                    {
                        [senderTableView.listOfItems removeObject:consolidatedItem];
                    }
                    [senderTableView reloadData];
                }
            }
        }
        [senderTableView.listOfItems removeObjectAtIndex:path.row];
    }
    [senderTableView deleteRowsAtIndexPaths:selectedRows withRowAnimation:UITableViewRowAnimationTop];

    //make new indexpaths for row animation
    NSMutableArray *newRows = [[NSMutableArray alloc] init];
    for (int i = 0; i < targetRows.count; i++) 
    {
        NSIndexPath *newPath = [NSIndexPath indexPathForRow:i+receiverTableView.listOfItems.count inSection:0];
        [newRows addObject:newPath];
        DLog(@"%i", i);

        //scroll to newest items
        [receiverTableView setContentOffset:CGPointMake(0, fmaxf(receiverTableView.contentSize.height - recieverTableView.frame.size.height, 0.0)) animated:YES];
    }

    //add rows at target
    for (int i = 0; i < targetRows.count; i++) 
    {
        MyCellObject *insertedItem = [targetRows objectAtIndex:i];

        //all moved items will be brought into the standard (basic) consolidationType
        insertedItem.consolidatedState = ConsolidationTypeBasic;

        [receiverTableView.ListOfItems insertObject:insertedItem atIndex:receiverTableView.ListOfItems.count];
    }

    [receiverTableView insertRowsAtIndexPaths:newRows withRowAnimation:UITableViewRowAnimationNone];
}

如果有人有一些关于为什么运动被烦扰的新想法让我知道。如果您觉得需要一些额外的信息,我会很乐意添加它。 问题再次出现在ChildCells的移动和正确更新ParentCells上。

我可以使用一些新鲜的外表和局外人的想法。

提前致谢。


*根据评论更新

使用此代码时,有2个Bug尚未解决:

错误1:全部选择它们,然后移动它们会留下一个子单元格 错误2:当Parent-Child-Child是列表中的最后3个项目,然后您尝试全部选择它们并移动它们时会崩溃。

此时单项运动再次完美。


当你认为它超过一个bug仍然存在时: 当您从ParentCell移动除了单个ChildCell之外的所有ChildCell时,ChildCell将不会更改回BasicCell。这是一个需要添加的重要方面,因为它可能会破坏桌面上的第二个动作。

当您遇到以下情况时:

P-C-C-C-C-P-C-C

你选择(用x标记)像这样:

P-C-C-C-C-P-C-CX

在运动之后它就像这样:

P-C-C-C-C-C

期待: P-C-C-C-C-B

下次制作时,这会使动作搞砸。 这里的父母的数量为4.但是它背后有5个子单元。 当您现在选择这样的单元格时:

P-CX-C-CX-C-CX

预期时

: P-CX-C-CX-C-BX

父母不应该被删除,因为只选择了4个孩子中的2个。但是由于之前的运动和现在的代码,他会认为它的3个孩子被移除并将返回:

C-C

虽然预期: P-C-C

更换数据源中的项目被证明是一项可怕的任务。它似乎没有坚持下去。


现在也解决了最后一个错误。

该错误是由错误计算孩子的索引引起的。由于数据源还没有更新,我需要检查父子结构中孩子的哪个索引仍然存在,并将其添加到j而不是仅仅+1

我在newItem.quantity == 1检查

后添加的这篇文章
     //replace the one child that is left and make it basic
                int x;
                for (x = 1; x<consolidatedItem.quantity; x++) 
                {
                    MyCell *cell = (MyCell *)[sender cellForRowAtIndexPath:[NSIndexPath indexPathForRow:x+j inSection:0]];
                    if (![cell isSelected]) 
                    {
                        break;
                    }
                }

                MyCellItem *lastChild = [sender objectAtIndex:j+x];
                MyCellItem *newChild = [lastChild copyToConsolidatedStateBasic];
                [sender.listOfItems replaceObjectAtIndex:j+x withObject:newChild];

1 个答案:

答案 0 :(得分:1)

更新:此代码实际上存在很多问题。原则上,一旦从主数组中删除了父行,存储在selectedRows数组的NSIndexPaths中的值就会变得过时。

这是经过测试和运行的代码(使用OP后)

for (int i = selectedRows.count-1; i >= 0; i--) 
{
    NSIndexPath *path = [selectedRows objectAtIndex:i];

    //check what item you are deleting. act upon the status. Parent- and HoldingCells cant be selected, so the only check that will be made are on child and basic cells
    MyCellObject *item = [sender.listOfItems objectAtIndex:path.row];
    if (item.consolidatedState == ConsolidationTypeChild) 
    {
        for (int j = path.row; j >= 0; j--) 
        {
            MyCellObject *consolidatedItem = [sender.listOfItems objectAtIndex:j];
            if (consolidatedItem.consolidatedState == ConsolidationTypeParent) 
            {
                //copy the consolidated item but with 1 less quantity
                MyCellObject *newItem = [consolidatedItem copyWithOneLessQuantity];

                if (newItem.quantity > 1)
                {
                    newItem.consolidatedState = ConsolidationTypeParent;
                    [sender.listOfItems replaceObjectAtIndex:j withObject:newItem];
                }
                else if (newItem.quantity == 1)
                {
                    MyCellObject *child = [sender.listOfItems objectAtIndex:j+1];
                    child.consolidatedState = ConsolidationTypeBasic;
                    [sender.listOfItems replaceObjectAtIndex:j+1 withObject:child];
                }

                if (newItem.quantity <= 1) {

                    [sender.listOfItems removeObjectAtIndex:j];

                    // Update indexPath row values for selected items that are above the removed row

                    for (int k = i; k >= 0; k--)
                    {
                        NSIndexPath *aPath = [selectedRows objectAtIndex:k];
                        if (aPath.row >= j) 
                        {
                            [selectedRows replaceObjectAtIndex:k withObject:[NSIndexPath indexPathForRow:(aPath.row -1) inSection:0]];
                        }
                        else 
                        {
                            break;
                        }
                    }  

                    path = [NSIndexPath indexPathForRow:(path.row -1) inSection:0]
                }
            }
        }
    }

    [sender.listOfItems removeObjectAtIndex:path.row];