2012-03-31 7 views
2

私はマルチセクションテーブルビューを持っています。編集モードでは、あるセクションから別のセクションに行を移動させることができます。 1つのセクションから最後の行が削除されると、そのセクションが削除されます。だから私はmoveRowAtIndexPath内でdeleteSectionを使用しています。セクションの最後の行を移動してセクションを削除すると奇妙なアニメーション

最後の項目をセクションから移動すると、セクションヘッダーが計画通りに消えます。しかし、非常に奇妙なアニメーションバグがあります。移動した行が上にドロップされた行と「マージ」し、空の行が「to」セクションの下部に表示されます(おそらくそのセクションのnumberOfRowsが正しいが、2行は同じ位置にある)。見知らぬ人でも、この行のリオーダーコントロールをクリックすると(アイテムを動かさずに単にタッチして離す)、2つのアイテムは「アンマージ」されます。

私はvideoを掲載しています。

私はデータの変更をラッピングし、変更を開始/終了の更新で表示しようとしましたが、役に立たないものです。

私はテストプロジェクトhereをアップロードしましたが、以下のコードも掲載します。いくつかのポイント:

  • データソースのフォーマットをデモプロジェクトで複製しようとしました。問題が発生した場所の場合です。重要なのは、私のソースは2つの他の配列の複合配列です(しかし、なぜこれが問題になるのか分かりません)。
  • 問題の動作を確認するには、下部のセクションの2つの行を上部のセクションに移動します。しかし、一番上のセクションの最後の行にドロップしないでください。これはうまくいくようです。
  • このデモプロジェクトでは、行を上から下に移動する方法がバグです。

コード(これのすべては、デモプロジェクトである):

私はloadViewメソッドで私の配列を設定します。私はまた、これらの組み合わせを返すメソッドを持っている

- (void)loadView{ 
array1 = [NSMutableArray array]; 
[array1 addObject:@"test 0"]; 
[array1 addObject:@"test 1"]; 
[array1 addObject:@"test 2"]; 

    array2 = [NSMutableArray array]; 
    [array2 addObject:@"test a"]; 
    [array2 addObject:@"test b"]; 

    [super loadView]; 
} 

配列 - データソースとして使用されます。

- (NSMutableArray *)sourceArray{ 
NSMutableArray *result = [NSMutableArray array]; 
if (array1.count > 0) { 
    [result addObject:array1]; 
} 
if (array2.count >0) { 
    [result addObject:array2]; 
    } 
    return result; 
} 

これは、非常に単純な数のro WS /セクション:

- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView 
{ 
    // Return the number of sections. 
    return self.sourceArray.count; 
} 

- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section 
{ 
    // Return the number of rows in the section. 
    return [[self.sourceArray objectAtIndex:section] count]; 
} 

スタンダードセル/ヘッダーの書式:

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath 
{ 
    static NSString *CellIdentifier = @"Cell"; 
    UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier]; 
    cell.textLabel.text = [[self.sourceArray objectAtIndex:indexPath.section] objectAtIndex:indexPath.row]; 
    return cell; 
} 
- (NSString *)tableView:(UITableView *)tableView titleForHeaderInSection:(NSInteger)section { 
    return [NSString stringWithFormat:@"Section %i", section]; 
} 

私はあなたの行または何が内側だとオフのチャンスで魔法

// Override to support rearranging the table view. 
- (void)tableView:(UITableView *)tableView moveRowAtIndexPath:(NSIndexPath *)fromIndexPath toIndexPath:(NSIndexPath *)toIndexPath 
{ 
    NSMutableArray *fromArray = [self.sourceArray objectAtIndex:fromIndexPath.section]; 
    NSMutableArray *toArray = [self.sourceArray objectAtIndex:toIndexPath.section]; 

    NSString *movedObject = [[self.sourceArray objectAtIndex:fromIndexPath.section] objectAtIndex:fromIndexPath.row]; 

    [fromArray removeObject:movedObject]; 
    [toArray insertObject:movedObject atIndex:toIndexPath.row]; 

     if ([self.tableView numberOfRowsInSection: fromIndexPath.section] == 0) { 
      [self.tableView deleteSections:[NSIndexSet indexSetWithIndex:fromIndexPath.section] withRowAnimation:UITableViewRowAnimationFade]; 
     } 
    } 
+1

なぜあなたは-loadViewであなたの配列を設定していますか?プログラムでビューを作成する場合は、-loadViewをオーバーライドする必要があります。いいえ? [super loadView]を呼び出すと、問題のView Controllerと同じ名前のペンがロードされます。配列の設定を-viewDidLoadに移動しないでください。 –

+0

ありがとう - このルールがどこから来たのかについてのリンク/詳細情報はありますか?もちろん、私の質問には役に立たないが、チップに感謝する。 –

+0

の場合は、nibでビューを設定している場合、OSによってloadViewが呼び出されるためです。メソッドのドキュメントでは、このメソッドを直接呼び出さないように明示し、ペン先からビューをロードしている場合はオーバーライドしないように明示しています。 – jmstone617

答えて

3

私は、削除されるセクションから来る行が、注文コントロールを修正するまで消える行であることに気付きました。

このデータソースメソッドがtableviewによって呼び出されたとき、その状態はまだ移動を実行中であると思われます。したがって、 'deleteSections'を呼び出すと、テーブルが移動している行を削除しようとします。セクションヘッダーと同じ割合で消え去るという事実と同じようにマージするのではなく、その下にあるものがスペースを埋めるためにバックアップを取っているだけです。

コントロールをタップすると、テーブルビューが再表示され、行が実際には消えないことがわかります。これは、削除はまだメインスレッド上で実行させますが、できるようになります

if ([self.tableView numberOfRowsInSection: fromIndexPath.section] == 0) { 
    dispatch_async(dispatch_get_main_queue(), ^() { 
     [self.tableView deleteSections:[NSIndexSet indexSetWithIndex:fromIndexPath.section] withRowAnimation:UITableViewRowAnimationFade]; 
    }); 
} 

:試してみて、この問題を回避、次の実行ループで削除を実行してみて、ディスパッチコールを経由して、好きに

'moveRow'と何らかの呼び出しスタックがあって、削除呼び出しの前にそのロジックを終了している場合

+0

ありがとうございます。 performSelector:withObject:afterDelay :?を使用して、これをソリューションと比較してどのように比較しますか?どちらの賛否両論もありますか? PS私はそこにあると思います。行方不明 - それは私が少なくとも6文字のために自分自身を行うための編集が小さすぎる –

+0

少し読んだ後、GCDは本当にこれを行う新しく輝く方法だと思われる。再度、感謝します! –

+1

performSelectorバリアントの欠点は、使用可能なメソッドのシグネチャを制限することです。これは問題ではありませんでしたが、2つのメソッドまたは3つのパラメータを持つメソッドを呼び出す必要がある場合、performSelectorを使用してそのメソッドを実行することはできません。それ以外の場合、0.0の遅延は本質的に同じです(ASAPを実行しますが、次の実行ループ中に実行されます) – bobDevil

0

を行うところです彼らは、あなたがresignFirstResponderまたは[view endEditing:YES]と呼んだことを確認しましたか?私たちがテキストフィールドを使用したときにこれを確認しました。(IIRCもバージョンに依存していました)、フィールドの1つにフォーカスが置かれました。

+0

私のテストプロジェクトにこのようなものが含まれていないことを確認しました。しかし、提案をありがとう。 –

0

セクションを削除した後、テーブルビューをリロードする必要があります。このコードを試してください。

- (void)tableView:(UITableView *)tableView moveRowAtIndexPath:(NSIndexPath *)fromIndexPath toIndexPath:(NSIndexPath *)toIndexPath 
{ 
    NSMutableArray *fromArray = [self.sourceArray objectAtIndex:fromIndexPath.section]; 
    NSMutableArray *toArray = [self.sourceArray objectAtIndex:toIndexPath.section]; 

    NSString *movedObject = [[self.sourceArray objectAtIndex:fromIndexPath.section] objectAtIndex:fromIndexPath.row]; 

    [fromArray removeObject:movedObject]; 
    [toArray insertObject:movedObject atIndex:toIndexPath.row]; 

     if ([self.tableView numberOfRowsInSection: fromIndexPath.section] == 0) { 
      [self.tableView deleteSections:[NSIndexSet indexSetWithIndex:fromIndexPath.section] withRowAnimation:UITableViewRowAnimationFade]; 
      [self.tableView reloadData]; 
     } 

    } 
+0

私はアニメーションを失いたくないし、私が見ている動作を説明していない。私のアプリケーションのどこかで、アニメーションのあるセクションを削除することができます。moveRowメソッドの内部で問題を発見しようとするときだけです。 –

0

は、あなたのコード内のfromArraytoArrayの順番を入れ替えます。アイテムが配列から削除される前に1の保持カウントを持っている場合、それはtoArrayにそれを加える前に0の保持カウントを持つでしょう。

注文を入れ替えると、削除が完了するとアイテムは1から2の保持数から1に戻ります。

+0

チップをありがとうが、これは何の違いもないようだ。私はそれが結果の場合、ARCを使用しています。 –

0

私はUITableViewRowAnimationFadeアニメーションがUITableViewCellムーブアニメーションを妨害していると思います。試してみることの1つは、セルの移動行のアニメーションが終了するようにセクションの削除を少し遅らせることです。

コードを次のコードに置き換えてください。

-(void)deleteSection:(NSIndexSet*)indexSet 
{ 
    [self.tableView deleteSections:indexSet withRowAnimation:UITableViewRowAnimationFade]; 
} 

// Override to support rearranging the table view. 
- (void)tableView:(UITableView *)tableView moveRowAtIndexPath:(NSIndexPath *)fromIndexPath toIndexPath:(NSIndexPath *)toIndexPath 
{ 
    NSMutableArray *fromArray = [self.sourceArray objectAtIndex:fromIndexPath.section]; 
    NSMutableArray *toArray = [self.sourceArray objectAtIndex:toIndexPath.section]; 

    NSString *movedObject = [[self.sourceArray objectAtIndex:fromIndexPath.section] objectAtIndex:fromIndexPath.row]; 

    [fromArray removeObject:movedObject]; 
    [toArray insertObject:movedObject atIndex:toIndexPath.row]; 

    if ([self.tableView numberOfRowsInSection: fromIndexPath.section] == 0) { 
     [self performSelector:@selector(deleteSection:) withObject:[NSIndexSet indexSetWithIndex:fromIndexPath.section] afterDelay:1.0]; 
//  [self.tableView deleteSections:[NSIndexSet indexSetWithIndex:fromIndexPath.section] withRowAnimation:UITableViewRowAnimationFade]; 
    } 
} 
1

問題はアニメーションにあります。もう一方がまだ終了していない間に(アニメーション削除&)、一方のセルが他方のセルに描画されます。これを確認するには、セルをもう一度動かします。正しい順序が表示されます。 AppleのdocsのUITableView上によると:

注:データソースはsetEditingを呼び出すべきではありません:アニメーション:のtableViewの実装内から:commitEditingStyle:forRowAtIndexPath :.何らかの理由で必要な場合は、performSelector:withObject:afterDelay:メソッドを使用して遅延の後に呼び出す必要があります。したがって、この問題を解決するために

、あなたのコードに次の操作を行います。

if ([self.tableView numberOfRowsInSection: fromIndexPath.section] == 0) { 
    [self performSelector:@selector(someMethod:) withObject:fromIndexPath afterDelay:1.0]; 
} 

- (void) someMethod:(NSIndexPath *) fromIndexPath { 
[self.tableView deleteSections:[NSIndexSet indexSetWithIndex:fromIndexPath.section] withRowAnimation:UITableViewRowAnimationFade]; 
} 

が正常に動作する必要があります。遅れを何か短いものに変更して、あなたをスイートにします。最後の行にアニメーションを失った

0

ソリューション:

if([listOfItemsOnTransaction count]==indexPath.row){ 
    [self.tableView deleteRowsAtIndexPaths:[NSArray arrayWithObjects:indexPath, nil]  
    withRowAnimation:UITableViewRowAnimationFade]; 
    [self.tableView reloadData]; 
    }else 
    { 
     [self.tableView deleteRowsAtIndexPaths:[NSArray arrayWithObjects:indexPath, nil] 
     withRowAnimation:UITableViewRowAnimationFade]; 


    }