UITableViewセクションヘッダーのデフォルトのスクロール動作を変更


147

2つのセクションを持つUITableViewがあります。シンプルなテーブルビューです。これらのヘッダーのカスタムビューを作成するために、viewForHeaderInSectionを使用しています。ここまでは順調ですね。

デフォルトのスクロール動作では、セクションが検出されると、次のセクションがスクロールして表示されるまで、セクションヘッダーがナビゲーションバーの下に固定されます。

私の質問はこれです:セクションヘッダーが上部に固定されないようにデフォルトの動作を変更できますが、ナビゲーションバーの下で残りのセクション行をスクロールできますか?

私は何か明白なものを見逃していますか?

ありがとう。


1
これは、このサイトで最もよく書かれた質問の1つであるに違いありません。:)ありがとう。
Fattie 2013年

1
この効果を達成するための正しい方法はこちらをチェックstackoverflow.com/a/13735238/1880899
スミットAnantwar

回答:


175

私がこの問題を解決した方法contentOffsetcontentInset、次のようにUITableViewControllerDelegate(extends UIScrollViewDelegate)に従ってを調整することです:

- (void)scrollViewDidScroll:(UIScrollView *)scrollView {
       CGFloat sectionHeaderHeight = 40;
   if (scrollView.contentOffset.y<=sectionHeaderHeight&&scrollView.contentOffset.y>=0) {
       scrollView.contentInset = UIEdgeInsetsMake(-scrollView.contentOffset.y, 0, 0, 0);
   } else if (scrollView.contentOffset.y>=sectionHeaderHeight) {
       scrollView.contentInset = UIEdgeInsetsMake(-sectionHeaderHeight, 0, 0, 0);
   }
}

ここでの唯一の問題は、上にスクロールして戻るときに少しバウンスが緩むことです。


{注:「40」は、セクション0ヘッダーの正確な高さである必要があります。セクション0のヘッダーの高さより大きい数値を使用すると、指の感触が影響を受けることがわかります(「1000」のようにしてみてください。バウンス動作が上部で奇妙なように見えます)。番号がセクション0ヘッダーの高さに一致する場合、指の感触は完璧またはほぼ完璧のようです。}


1
上記より完璧なソリューション。
11

4
ありがとうございました!これは完璧なソリューションです。セクションフッターの解決策はありますか?
Tuan Nguyen

12
このソリューションは、メニューの上のタップを正しく処理しません。メニューバーは、リストの一番上までスクロールすることになっています。
リードエリス

scrollView.contentInset = UIEdgeInsetsMake(0、0、sectionHeaderHeight、0):uはセクションフッタービューに同じ動作が必要な場合は、ちょうどこのような最後の行を変更
アレックス

これで十分のようです:scrollView.contentInset = UIEdgeInsetsMake(scrollView.contentOffset.y> = 0?-scrollView.contentOffset.y:0、0、0、0);
MacMark 2013

85

また、上部に行がゼロのセクションを追加して、前のセクションのフッターを次のセクションのヘッダーとして使用することもできます。


13
私は2つの以上のセクションを持っている私の場合は、意志のアンカー下部に..フッター
ジョセフ・林

3
これはクリエイティブですが、NSFetchedResultsControllerを使用してテーブルをロードする場合は、indexPathを調整する必要があります。
XJones

+1最高のソリューション-実装するのに3行ほどかかりました!
2012年

ブリリアントブリリアントブリリアント:-)
iphonic 2013

これはアンカーするフッターに対してどのように機能しますか?いくつかの助けに感謝します!ありがとう
darwindeeds 2013年

36

私がこれを行っていたなら、プレーンスタイルのUITableViewにはスティッキーヘッダーがあり、グループ化スタイルのヘッダーにはないという事実を利用します。おそらく、少なくともカスタムテーブルセルを使用して、グループ化されたテーブルのプレーンセルの外観を模倣してみます。

私は実際にこれを試していないので、うまくいかないかもしれませんが、それは私が行うことをお勧めするものです。


おそらく機能しますが、試されましたか?そして、@ voidSternの答えが完全に機能するとき、それは多くの仕事のように見えます!!
ベンフォード2011

セクションが3つ以上ある場合、voidSternの回答は機能しません。コリンの答えは、セクション番号を手動でシフトしたりセクション数を追加したりする必要がなく、よりシンプル/よりエレガントです。
ジョセフ・リン

ヒント:tableView.separatorColor = [UIColor clearColor];プレーンテーブルビューを模倣するために使用します。
ジョセフ・リン

3
これを試してみましたが、グループ化されたテーブルセルをプレーンなセルのように見せることができなかった場合、つまり、セルの左右のマージンを削除しました。どうやってやったの?
アダムカーター

1
UITableViewStyle、つまりグループ化されたプレーンについて明確にすることに感謝します。これにより、テーブルビューのセクションヘッダー/フッターがスティッキーになるかどうかが決まります。@Colin Barrettに感謝
Dhaval H. Nena

28

遅くなることはわかっていますが、最終的な解決策を見つけました。

あなたがしたいことは、10個のセクションがある場合、dataSourceが20を返すようにすることです。セクションヘッダーには偶数を使用し、セクションコンテンツには奇数を使用します。このようなもの

- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
    if (section%2 == 0) {
        return 0;
    }else {
        return 5;
    }
}

-(NSString *)tableView:(UITableView *)tableView titleForHeaderInSection:(NSInteger)section {
    if (section%2 == 0) {
        return [NSString stringWithFormat:@"%i", section+1];
    }else {
        return nil;
    }
}

ボイラ!:D


いい案。しかし、セクションインデックスのタイトルがある場合、これが混乱するのではないかと思います。
roocell

どうして?セクションのタイトルでも同じことができます。奇数の場合はnilを、偶数の場合はタイトルを覚えてください。
LocoMike、2012年

1
はい-この方法はうまくいきます。それはたくさんの簿記でした(おそらく私がセクションタイトルを取得しなければならない方法と関係があります)しかしそれはうまくいきました。コツは、numberOfRowsInSectionとcellForRowAtIndexPathがif(section%2!= 0 && section!= 0)を使用するのに対し、titleForHeaderInSectionと他のセクションインデックス関数はif(section%2 == 0)を使用することです
roocell

発信者はこれを答えとして選択する必要があります。セクションタイトルを自動的にアンカーするuitableviewをサブクラス化する方法があったら、すばらしいと思います。
roocell 2012年

これは私にとって最も効果的でした。私は最初に@Colinのソリューションを試しましたが、使用している大幅にカスタマイズさUITableViewれたソリューションではうまく機能しませんでした。
kubi

15

この問題をハッキングされない方法で解決するには、いくつかのことを行う必要があります。

  1. テーブルビュースタイルを UITableViewStyleGrouped
  2. テーブルビューbackgroundColor[UIColor clearColor]
  3. 設定するbackgroundViewと、空のビューに各テーブルビューセル上をbackgroundColor [UIColor clearColor]
  4. 必要に応じて、テーブルビューをrowHeight適切に設定するtableView:heightForRowAtIndexPath:か、個々の行の高さが異なる場合はオーバーライドします。

(+1)@ニール、私はあなたの答えを試しましたが、残念ながら、UITableViewStyleGroupedテーブルのセルにはヘッダーとの配置を変更する余分なマージンがあるためです。これは、実際に複数列のテーブルを描き、ヘッダーを使用して列のタイトルを表示する(そして、個々のテーブルエントリをこれらのタイトルに合わせる)場合に問題になります。
ブレインジャム2011

15

最初にここに掲載された、IBを使用した簡単な解決策。非常に単純ですが、プログラムで同じことを行うことができます。

これを実現するためのおそらくより簡単な方法(IBを使用):

UIViewをTableViewにドラッグして、ヘッダービューにします。

  1. ヘッダービューの高さを100pxに設定します
  2. テーブルビューのcontentInset(トップ)を-100に設定します。
  3. セクションヘッダーは、通常のセルと同じようにスクロールします。

このソリューションは最初のヘッダーを隠すと言っている人もいますが、私はそのような問題に気づいていません。これは完璧に機能し、これまで見た中で最も簡単なソリューションでした。


おそらくビューをクリアカラーの背景色を使用するように設定する必要があることに注意してください。それ以外の場合は、上をスクロールするとバウンスに白が表示されます。
Doc

3
それは私の最初のヘッダーを隠す
リーナ

リーナ、実行しているiOSのバージョンは?ビューはUITableViewControllerですか、それともUITableViewが含まれているUIViewですか?一部の人にとってこのソリューションが最初のヘッダーを非表示にする理由がわからないので、矛盾を見つけようとしています。
ドク

このソリューションは完璧です。私は無限の上部と下部のセル背景の外観を探しています-これは完全にそれを達成します。いいね!
テイラーハリデー

このソリューションは優れています。このスレッドの他の回答よりも簡単に達成できます。私の意見では、これは受け入れられる答えであるはずです。
ジョンロジャース

15

これまでに説明したソリューションに満足できなかったので、それらを組み合わせてみました。結果は、@ awulfと@cescofryに触発された次のコードです。実際のテーブルビューヘッダーがないので、うまくいきます。すでにテーブルビューヘッダーがある場合は、高さを調整する必要があります。

// Set the edge inset
self.tableView.contentInset = UIEdgeInsetsMake(-23.0f, 0, 0, 0);

// Add a transparent UIView with the height of the section header (ARC enabled)
[self.tableView setTableHeaderView:[[UIView alloc] initWithFrame:CGRectMake(0.0f, 0.0f, 100.0f, 23.0f)]];

これは私が見つけた最も簡単な解決策でした。
Zorayr 2013年

これはiOS9.2で動作しました。古い回答ですが、まだ有効です。そして、それは最初のセクションヘッダーを隠しませんでした。動作し、完全に動作します。
idStar 2016年

完璧です。テーブルビューに既にヘッダーがある場合は、その高さをオフセット分だけ増やしてから、ヘッダーコンテンツの上部の制約定数を増やして、コンテンツを元の位置にシフトします
Jason

14

TableViewスタイルを変更するだけです。

self.tableview = [[UITableView alloc] initwithFrame:frame style:UITableViewStyleGrouped];

UITableViewStyleドキュメント

UITableViewStylePlain-プレーンテーブルビュー。セクションヘッダーまたはフッターはインラインセパレータとして表示され、テーブルビューがスクロールされるとフロートします。

UITableViewStyleGrouped-セクションが異なる行のグループを表示するテーブルビュー。セクションのヘッダーとフッターはフロートしません。


素晴らしい答え、私のために働きました。回避する必要はありません
Shams Ahmed


5

断面ビューのヘッダーと同じ高さの透明ビューでテーブルのheaderViewを設定します。また、-heightでyフレームを使用してテーブルビューを開始します。

self.tableview = [[UITableView alloc] initWithFrame:CGRectMake(0, - height, 300, 400)];

UIView *headerView = [[[UIView alloc] initWithFrame:CGRectMake(0, 0, width, height)] autorelease];
[self.tableView setTableHeaderView:headerView];

4

別の解決策を見つけました、実際のヘッダーセクションの代わりに各セクションの最初のセルを使用してください。このソリューションはそれほどきれいに見えませんが、うまく機能します。ヘッダーセクションに定義済みのプロトタイプセルを使用でき、メソッドcellForRowAtIndexPathで使用できます。 indexPath.row == 0を要求します。trueの場合、ヘッダーセクションのプロトタイプセルを使用します。それ以外の場合は、デフォルトのプロトタイプセルを使用します。


それでもindexPath.rowindexPath.sectionを使用したい場合は、ヘッダーが非表示になるように0.0fforの高さを返す- (CGFloat)tableView:(UITableView *)tableView heightForHeaderInSection:(NSInteger)sectionようにしてください。
スープ

4

TableViewスタイルを変更します。

self.tableview = [[UITableView alloc] initwithFrame:frame style:UITableViewStyleGrouped];

UITableViewのアップルのドキュメントに従って:

UITableViewStylePlain-プレーンテーブルビュー。セクションヘッダーまたはフッターはインラインセパレータとして表示され、テーブルビューがスクロールされるとフロートします。

UITableViewStyleGrouped-セクションが異なる行のグループを表示するテーブルビュー。セクションのヘッダーとフッターはフロートしません。この小さな変更がお役に立てば幸いです。


2

グループ化されたスタイルは基本的にiOS 7のプレーンスタイルと同じように見えますが(フラットネスと背景に関して)、テーブルビューのスタイルを単にグループ化するように変更するだけが最善で最も簡単な(つまり、ハックが最も少ない)修正でした。スクロールアウェイナビゲーションバーを上部に組み込んだとき、contentInsetsでのジャッキングは常に問題でした。グループ化されたテーブルビュースタイルでは、(セルを含めて)まったく同じに見え、セクションヘッダーは固定されたままです。スクロールの奇妙さはありません。


これは特にセルがカスタムの場合に最適なソリューションです。スクロールが上部にヒットしたときにセクションヘッダーの「保持」を停止するように見えます。
リサイクルスチール

1

tableViewに負のインセットを割り当てます。22pxの高さのセクションヘッダーがあり、reloadDataを追加した直後にそれらをスティッキーにしたくない場合は、次のように追加します。

self.tableView.contentInset = UIEdgeInsetsMake(-22, 0, 0, 0); 
self.tableView.contentSize = CGSizeMake(self.tableView.contentSize.width, self.tableView.contentSize.height+22); 

私にとっては魅力のように機能します。セクションフッターでも機能します。代わりに、下部に負のインセットを割り当てます。


これは最初のヘッダーを切り落とすだけですか?
cannyboy

私のために完全に働いた!! ありがとう
Daniel

0

スクロールビューにテーブルを追加しましたが、うまく機能しているようです。



0

@LocoMikeの回答は私のtableViewに最適でしたが、フッターを使用したときにも壊れました。したがって、これはヘッダーとフッターを使用する場合の正しい解決策です。

- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
{
    return (self.sections.count + 1) * 3;
}

- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
    if (section % 3 != 1) {
        return 0;
    }
    section = section / 3;
    ...
}

- (NSString *)tableView:(UITableView *)tableView titleForHeaderInSection:(NSInteger)section
{
    if (section % 3 != 0) {
        return nil;
    }
    section = section / 3;
    ...
}

- (CGFloat)tableView:(UITableView *)tableView heightForHeaderInSection:(NSInteger)section
{
    if (section % 3 != 0) {
        return 0;
    }
    section = section / 3;
    ...
}

- (CGFloat)tableView:(UITableView *)tableView heightForFooterInSection:(NSInteger)section
{
    if (section % 3 != 2) {
        return 0;
    }
    section = section / 3;
    ...
}

- (UIView *)tableView:(UITableView *)tableView viewForHeaderInSection:(NSInteger)section
{
    if (section % 3 != 0) {
        return nil;
    }
    section = section / 3;
    ...
}

- (UIView *)tableView:(UITableView *)tableView viewForFooterInSection:(NSInteger)section
{
    if (section % 3 != 2) {
        return nil;
    }
    section = section / 3;
    ...
}

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
    int section = indexPath.section;
    section = section / 3;
    ...
}

0

@awulf回答のSwiftバージョン。

func scrollViewDidScroll(scrollView: UIScrollView) {
    let sectionHeight: CGFloat = 80
    if scrollView.contentOffset.y <= sectionHeight {
        scrollView.contentInset = UIEdgeInsetsMake( -scrollView.contentOffset.y, 0, 0, 0)
    }else if scrollView.contentOffset.y >= sectionHeight {
        scrollView.contentInset = UIEdgeInsetsMake(-sectionHeight, 0, 0, 0)
    }
}

-2

tableHeaderViewプロパティを設定するだけで実行できることを学びました。

 tableView.tableHeaderView = customView;

以上です。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.