5

クリック可能なセクションを含むUITableviewを作成しました。それらをクリックすると、

  1. それらは「拡張」してその中の細胞を明らかにします
  2. クリックしたセクションがビューの上部にスクロールします。

必要なセルを挿入/削除するためにすべてのインデックスパスを計算してから、次のコードでそれらを挿入します。

[self.tableView beginUpdates];
[self.tableView insertRowsAtIndexPaths:pathsToOpen withRowAnimation:insertAnimation];
[self.tableView deleteRowsAtIndexPaths:pathsToClose withRowAnimation:deleteAnimation];
[self.tableView endUpdates];
[self.tableView scrollToRowAtIndexPath:[pathsToOpen objectAtIndex:0]  atScrollPosition:UITableViewScrollPositionTop animated:YES];

問題は1つだけです。選択したセクションの下のセクションが非表示になります。最初のスクリーンショットは、テーブルビューがどのように見えるかを示しています。2番目のスクリーンショットは、実際にどのように見えるかを示しています。

セクションが消える

上にスクロールして(非表示のセクションが画面外に表示されるように)、次に下にスクロールすると、非表示のセクションが元に戻ります(もう一度表示されます)。これが起こっている理由についての私の推測は次のとおりです。

挿入/削除アニメーションは同時に発生してscrollToRowAtIndexPathおり、TableViewを混乱させています。私がscrollToRowAtIndexPathセクション3と4を実行していなかったとしたら、画面外になっていたでしょう。そのため、tableViewはどういうわけかまだ画面外にあると考えています。UITableviewは、最適化として画面外にあるセル/セクションを非表示にします。2秒scrollToRowAtIndexPathでaを呼び出すと、セクション3と4が正しく表示されます。dispatch_after

したがって、これが発生している理由はわかっていると思いますが、このUITableviewの最適化を修正/オーバーライドする方法がわかりません。実際、scrollViewDidEndScrollingAnimationこの関数にブレークポイントを実装してから追加すると、アプリはセクション3と4を正しく表示します(これが最初のスクリーンショットを取得した方法です)。しかし、この機能を続けると、細胞は消えます。

プロジェクト全体はここからダウンロードできます


追加の実装の詳細:セクションは正当なUITableViewセクションです。テーブルビューへのデリゲートコールバックをトリガーするtapGestureRecognizerを追加しました。以下に含まれているのは、セクションを開くメソッド全体です。

- (void)sectionHeaderView:(SectionHeaderView *)sectionHeaderView sectionOpened:(NSInteger)sectionOpened
{
    // Open
    sectionHeaderView.numRows = DefaultNumRows;
    sectionHeaderView.selected = YES;
    NSMutableArray *pathsToOpen = [[NSMutableArray alloc] init];
    for (int i = 0; i < sectionHeaderView.numRows; i++)
    {
        NSIndexPath *pathToOpen = [NSIndexPath indexPathForRow:i inSection:sectionOpened];
        [pathsToOpen addObject:pathToOpen];
    }

    // Close
    NSMutableArray *pathsToClose = [[NSMutableArray alloc] init];
    if (openSectionHeader)
    {
        for (int i = 0; i < openSectionHeader.numRows; i++)
        {
            NSIndexPath *pathToClose = [NSIndexPath indexPathForRow:i inSection:openSectionHeader.section];
            [pathsToClose addObject:pathToClose];
        }
    }

    // Set Correct Animation if section's already open
    UITableViewRowAnimation insertAnimation = UITableViewRowAnimationBottom;
    UITableViewRowAnimation deleteAnimation = UITableViewRowAnimationTop;
    if (!openSectionHeader || sectionOpened < openSectionHeader.section)
    {
        insertAnimation = UITableViewRowAnimationTop;
        deleteAnimation = UITableViewRowAnimationBottom;
    }

    openSectionHeader.numRows = 0;
    openSectionHeader.selected = NO;
    openSectionHeader = sectionHeaderView;


    [self.tableView beginUpdates];
    [self.tableView insertRowsAtIndexPaths:pathsToOpen withRowAnimation:insertAnimation];
    [self.tableView deleteRowsAtIndexPaths:pathsToClose withRowAnimation:deleteAnimation];
    [self.tableView endUpdates];
    [self.tableView scrollToRowAtIndexPath:[pathsToOpen objectAtIndex:0]  atScrollPosition:UITableViewScrollPositionTop animated:YES];
}
4

2 に答える 2

6

私の知る限り、すでに使用されている断面図を返すときに問題が発生しています。それ以外の:

- (UIView *)tableView:(UITableView*)tableView viewForHeaderInSection:(NSInteger)section
{
    return [self.sectionHeaderViews objectAtIndex:section];
}

毎回新しいビューを作成しても問題はありません。

- (UIView *)tableView:(UITableView*)tableView viewForHeaderInSection:(NSInteger)section{
    SectionHeaderView *sectionHeaderView = [self.tableView dequeueReusableCellWithIdentifier:SectionHeaderView_NibName];
    sectionHeaderView.textLabel.text = [NSString stringWithFormat:@"Section %d", section];

    UITapGestureRecognizer *tapRecognizer = [[UITapGestureRecognizer alloc] initWithTarget:sectionHeaderView action:@selector(handleTap:)];
    [sectionHeaderView addGestureRecognizer:tapRecognizer];
    sectionHeaderView.section = section;
    sectionHeaderView.delegate = self;
    return sectionHeaderView;
}

これは、[self.tableView dequeueReusableCellWithIdentifier:SectionHeaderView_NibName];セクションヘッダーを作成し、配列内でそれらを保持するために使用しているために発生している可能性があります。これは、UITableViewCellが作成されたとは思われませんが、確かではありません。セクションビューについては前述のUITableViewCellを検討し、代わりに別のもの(おそらく、UILabelを持つUIImageView)を使用することをお勧めします。または、セクションビューを配列に格納することはできません...現在コードを設定している方法では、配列は必要ありません。新しいビューを作成するのは簡単で、心配する必要はありません。

于 2012-07-19T17:30:37.380 に答える
5

@AaronHaymanの答えは機能します(そして、IMOは受け入れと報奨金をそのまま彼に渡す必要があります-これはコメントに収まりませんでした!)、しかし私はさらに先に進みます-セクションにセルをまったく使用しないでくださいまた、基本的に nib をロードするためにデキュー メカニズムを使用するべきではありません。

セクション ヘッダー ビューはセルであると想定されていません。通常のビューの代わりにそれらを使用すると、特にそれらがデキューされた場合に予期しない効果が生じる可能性があります。これを行うと、テーブルはこれらの再利用可能なセルのリストを保持し、それらをリサイクルします。それらが画面から消えても、セクション ヘッダー再利用できない場合は、セクションごとに 1 つあります。

あなたのサンプル プロジェクトでは、SectionHeaderView のスーパークラスをプレーンな UIView に変更し、createSectionHeaderViewsメソッドをそこのペン先から直接ロードするように変更しました。

NSMutableArray *sectionHeaderViews = [[NSMutableArray alloc] init];
    UINib *headerNib = [UINib nibWithNibName:SectionHeaderView_NibName bundle:nil];
    for (int i = 0; i < 5; i++)
    {
        SectionHeaderView *sectionHeaderView = [[headerNib instantiateWithOwner:nil options:nil] objectAtIndex:0];
        sectionHeaderView.textLabel.text = [NSString stringWithFormat:@"Section %d", i];

        UITapGestureRecognizer *tapRecognizer = [[UITapGestureRecognizer alloc] initWithTarget:sectionHeaderView action:@selector(handleTap:)];
        [sectionHeaderView addGestureRecognizer:tapRecognizer];
        sectionHeaderView.section = i;
        sectionHeaderView.delegate = self;

        [sectionHeaderViews addObject:sectionHeaderView];
    }
    self.sectionHeaderViews = sectionHeaderViews;

また、viewDidLoad から再利用行の登録をコメントアウトしました。これにより、セクション ヘッダーが消えるのを防ぎます。

于 2012-07-20T11:44:17.717 に答える