静的セルに設定されたUITableView。プログラムで一部のセルを非表示にすることは可能ですか?


回答:


48

あなたはこの解決策を探しています:

StaticDataTableViewController 2.0

https://github.com/xelvenone/StaticDataTableViewController

アニメーションの有無にかかわらず、静的セルを表示/非表示/再読み込みできます!

[self cell:self.outletToMyStaticCell1 setHidden:hide]; 
[self cell:self.outletToMyStaticCell2 setHidden:hide]; 
[self reloadDataAnimated:YES];

常に(reloadDataAnimated:YES / NO)のみを使用することに注意してください([self.tableView reloadData]を直接呼び出さないでください)

これは、高さを0に設定したハッキーソリューションを使用せず、変更をアニメーション化してセクション全体を非表示にすることができます


6
このソリューションの1つの問題は、非表示のセルがあった場所にギャップが残ることです。
ジャック

ギャップの意味は?状況をより詳しく説明できますか、おそらく直接githubにいますか?サンプルを実行しましたか?
Peter Lapisu、2013

1
つまり、たとえば3つのセクションがあり、中央セクションからセルを非表示にした場合、そのセクションが残っていたスペースが残ります。サンプルプロジェクトは試していませんが、コードは試しました。サンプルを試してみましょう。
ジャック

1
サンプルを確認してください。より大きな更新があり、古いコードがあったかもしれません...私にとって完璧に機能します
Peter Lapisu

サンプルを試してみましたが、そこで機能しているようです。私が異なるのは、を使用するIBOutletCollectionことだけですが、それがどのように違いを生むのかわかりません。昨日だけコードをダウンロードしたので、古いバージョンではないと思います。
ジャック

164

UITableで静的セルを非表示にするには:

  1. このメソッドを追加します

UITableViewコントローラーデリゲートクラス:

Objective-C:

- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath
{
    UITableViewCell* cell = [super tableView:tableView cellForRowAtIndexPath:indexPath];

    if(cell == self.cellYouWantToHide)
        return 0; //set the hidden cell's height to 0

    return [super tableView:tableView heightForRowAtIndexPath:indexPath];
}

迅速:

override func tableView(tableView: UITableView, heightForRowAtIndexPath indexPath: NSIndexPath) -> CGFloat {
    var cell = super.tableView(tableView, cellForRowAtIndexPath: indexPath)

    if cell == self.cellYouWantToHide {
        return 0
    }

    return super.tableView(tableView, heightForRowAtIndexPath: indexPath)
}

このメソッドは、UITableのセルごとに呼び出されます。非表示にするセルに対して呼び出しを行ったら、高さを0に設定します。アウトレットを作成してターゲットセルを識別します。

  1. デザイナーで、非表示にするセルのアウトレットを作成します。このようなセルのアウトレットは、上記の「cellYouWantToHide」と呼ばれています。
  2. 非表示にするセルのIBで「サブビューをクリップ」をチェックします。非表示にするセルには、ClipToBounds = YESが必要です。そうでない場合、テキストはUITableViewに蓄積されます。

10
素晴らしい解決策。このClipToBounds問題を回避するには、セルを非表示に設定することもできます。これは私にはきれいに思えます。;-)
MonsieurDart

13
+1はClipToBounds = YESです。他のスレッドのNumeorusソリューションはそれを見逃しています。
ジェフ

2
いい案。これは私が見つけた最も簡単な解決策です。他のソリューションでは、2つ以上の場所にコードがありました。ところで、IBでは、ClipToBoundsは「Clip Subviews」としてリストされています。
VaporwareWolf 2014

1
少し修正して、この .cellYouWantToHideの代わりにself .cellYouWantToHideを使用しください。
Zoltan Vinkler、2015

2
セルオブジェクトを作成せずに、「index.row」を使用して「uitableviewcell」を非表示にすることもできます
g212gs

38

最善の方法は、次のブログhttp://ali-reynolds.com/2013/06/29/hide-cells-in-static-table-view/で説明されているとおりです。

静的なテーブルビューをインターフェイスビルダーで通常どおりに設計します–潜在的に非表示になっているすべてのセルを完備します。ただし、非表示にする可能性のあるすべてのセルに対して行う必要のあることが1つあります。セルの「Clip subviews」プロパティを確認してください。そうしないと、セルのコンテンツが非表示になっても(高さを縮小して)消えません。 - もっと後で)。

SO –セルにスイッチがあり、スイッチはいくつかの静的セルを非表示にして表示することになっています。それをIBActionに接続し、そこで実行します。

[self.tableView beginUpdates];
[self.tableView endUpdates];

これにより、セルの表示と非表示の素晴らしいアニメーションが得られます。次のテーブルビューデリゲートメソッドを実装します。

- (float)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath {
    if (indexPath.section == 1 && indexPath.row == 1) { // This is the cell to hide - change as you need
    // Show or hide cell
        if (self.mySwitch.on) {
            return 44; // Show the cell - adjust the height as you need
        } else {
            return 0; // Hide the cell
        }
   }
   return 44;
}

以上です。スイッチを押すと、セルが非表示になり、スムーズなアニメーションで再表示されます。


更新:セルのラベルをセルの非表示/表示に設定する必要もあります。そうしないと、ラベルが混乱します。
Mohamed Saleh 2013年

1
静的セルのコンテンツ内のUIViewにcell.contentに対する制約がある場合、それらの制約が新しいセルの高さに対して無効になると、ランタイムエラーが発生する可能性があることに注意してください。
Pedro Borges 14

1
ベストアンサー。ありがとう。
Eric Chen

1
このトリックが動的コンテンツで機能することを知っていました。staticでもかなりうまく動作します。とても簡単です。
Ants 2015年

2
これは実際に機能しますが、不足している点をカバーします。非表示/表示する行に日付ピッカーが含まれている場合は、[self.tableView beginUpdates]のみを実行します。[self.tableView endUpdates]; それを隠している間、まだグリッチを残します。グリッチを解消するには、[self.tableView reloadRowsAtIndexPaths:@ [indexPathOfTargetRow] withRowAnimation:UITableViewRowAnimationNone]を呼び出す必要があります。また、ここでは行アニメーションが何らかの形で「無効」になっていることに注意してください。
Chris

34

私の解決策はGarethと同様の方向に進みますが、私はいくつかのことを異なる方法で行います。

ここに行く:

1.セルを非表示にする

セルを直接非表示にする方法はありません。UITableViewControllerは静的セルを提供するデータソースであり、現在、「セルxを提供しない」ことを通知する方法はありません。そのUITableViewControllerため、静的セルを取得するためににデリゲートする独自のデータソースを提供する必要があります。

最も簡単なのは、サブクラス化しUITableViewControllerセルを非表示にするときに異なる動作が必要なすべてのメソッドをオーバーライドすることです。

最も単純なケース(単一のセクションテーブル、すべてのセルの高さが同じ)では、次のようになります。

- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section    
{
    return [super tableView:tableView numberOfRowsInSection:section] - numberOfCellsHidden;
}

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
    // Recalculate indexPath based on hidden cells
    indexPath = [self offsetIndexPath:indexPath];

    return [super tableView:tableView cellForRowAtIndexPath:indexPath];
}

- (NSIndexPath*)offsetIndexPath:(NSIndexPath*)indexPath
{
    int offsetSection = indexPath.section; // Also offset section if you intend to hide whole sections
    int numberOfCellsHiddenAbove = ... // Calculate how many cells are hidden above the given indexPath.row
    int offsetRow = indexPath.row + numberOfCellsHiddenAbove;

    return [NSIndexPath indexPathForRow:offsetRow inSection:offsetSection];
}

テーブルに複数のセクションがある場合、またはセルの高さが異なる場合は、より多くのメソッドをオーバーライドする必要があります。ここでも同じ原則が適用されます。スーパーに委任する前に、indexPath、section、rowをオフセットする必要があります。

またdidSelectRowAtIndexPath:、同様のメソッドのindexPathパラメータは、状態(つまり、非表示のセルの数)に応じて、同じセルに対して異なります。そのため、indexPathパラメータを常にオフセットし、これらの値を操作することをお勧めします。

2.変更をアニメーション化する

Garethがすでに述べたように、reloadSections:withRowAnimation:メソッドを使用して変更をアニメーション化すると、大きな不具合が発生します。

reloadData:その後すぐに電話をかけると、アニメーションが大幅に改善されることがわかりました(わずかな不具合が残っただけです)。テーブルはアニメーション後に正しく表示されます。

だから私がやっていることは:

- (void)changeState
{
     // Change state so cells are hidden/unhidden
     ...

    // Reload all sections
    NSIndexSet* reloadSet = [NSIndexSet indexSetWithIndexesInRange:NSMakeRange(0, [self numberOfSectionsInTableView:tableView])];

    [tableView reloadSections:reloadSet withRowAnimation:UITableViewRowAnimationAutomatic];
    [tableView reloadData];
}

2
あなたを祝福します、あなたは甘い甘い人です。
guptron 2013

マイナーなアニメーションの不具合の解決策を見つけましたか?私にとって、セル間の区切り線は正しくアニメーション化されず、グリッチされたアニメーションよりもアニメーションを使用しません。素晴らしい解決策ですが!
MaximilianKörner2013年

私の問題は、静的セルでnumberOfRowsInSection:は、テーブルが初めてロードされたときにのみ呼び出されるということです。[self.tableView reloadData]を呼び出したとき- numberOfRowsInSection:再び呼び出されることはありません。cellForRowAtIndexPath:呼ばれるだけです。何が欠けていますか?
ローマ

13
  1. デザイナーで、非表示にするセルのアウトレットを作成します。たとえば、「cellOne」を非表示にしたいので、viewDidLoad()でこれを行います

cellOneOutlet.hidden = true

以下のメソッドをオーバーライドして、非表示になっているセルのステータスを確認し、それらのセルの高さ0を返します。これは、static tableViewのセルをすばやく非表示にする方法の1つです。

override func tableView(tableView: UITableView, heightForRowAtIndexPathindexPath: NSIndexPath) -> CGFloat 
{

let tableViewCell = super.tableView(tableView,cellForRowAtIndexPath: indexPath)

        if tableViewCell.hidden == true
        {
            return 0
        }
        else{
             return super.tableView(tableView, heightForRowAtIndexPath: indexPath)
        }

}

これまでのベストソリューション!
derdida、2016

変更を加えた後、tableView.reloadData()を追加すれば完璧です。ソリューションを変更するための多くの労力を節約できました!おかげで
シャヤンC

1
Swift 4では使用できませんlet tableViewCell = super.tableView(tableView,cellForRowAtIndexPath: indexPath)。に置き換えられたと思いlet tableViewCell = tableView.cellForRow(at: indexPath as IndexPath)ます。
Clifton Labrum

で静的セルを使用しているためUITableViewControllerUITableViewデリゲートメソッドはありません。それを呼び出すためにheightForRow、他のメソッドも必要ですか?
クリフトンラブラム

@CliftonLabrumいいえ、このメソッドのみをオーバーライドできます。
Alexander Ershov

11

実際にセクションを非表示にし、セクションを削除しない代替案を思いつきました。@ henning77のアプローチを試しましたが、静的UITableViewのセクション数を変更すると、問題が発生し続けました。この方法は私にとっては本当にうまくいきましたが、私は主に行ではなくセクションを非表示にしようとしています。一部の行をその場で正常に削除していますが、かなり面倒なので、表示または非表示にする必要があるセクションにグループ化しようとしました。以下は、セクションを非表示にする方法の例です。

まず、NSMutableArrayプロパティを宣言します

@property (nonatomic, strong) NSMutableArray *hiddenSections;

viewDidLoadで(またはデータを照会した後)、非表示にするセクションを配列に追加できます。

- (void)viewDidLoad
{
    hiddenSections = [NSMutableArray new];

    if(some piece of data is empty){
        // Add index of section that should be hidden
        [self.hiddenSections addObject:[NSNumber numberWithInt:1]];
    }

    ... add as many sections to the array as needed

    [self.tableView reloadData];
}

次に、以下のTableViewデリゲートメソッドを実装します。

- (NSString *)tableView:(UITableView *)tableView titleForHeaderInSection:(NSInteger)section
{
    if([self.hiddenSections containsObject:[NSNumber numberWithInt:section]]){
        return nil;
    }

    return [super tableView:tableView titleForHeaderInSection:section];
}

- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath
{
    if([self.hiddenSections containsObject:[NSNumber numberWithInt:indexPath.section]]){
        return 0;
    }

    return [super tableView:tableView heightForRowAtIndexPath:[self offsetIndexPath:indexPath]];
}

- (void)tableView:(UITableView *)tableView willDisplayCell:(UITableViewCell *)cell forRowAtIndexPath:(NSIndexPath *)indexPath
{
    if([self.hiddenSections containsObject:[NSNumber numberWithInt:indexPath.section]]){
        [cell setHidden:YES];
    }
}

次に、高さを0に設定できないため、非表示セクションのヘッダーとフッターの高さを1に設定します。これにより、2ピクセルのスペースが追加されますが、次の表示されるヘッダーの高さを調整することで埋め合わせることができます。

-(CGFloat)tableView:(UITableView *)tableView heightForHeaderInSection:(NSInteger)section 
{
    CGFloat height = [super tableView:tableView heightForHeaderInSection:section];

    if([self.hiddenSections containsObject:[NSNumber numberWithInt:section]]){
        height = 1; // Can't be zero
    }
    else if([self tableView:tableView titleForHeaderInSection:section] == nil){ // Only adjust if title is nil
        // Adjust height for previous hidden sections
        CGFloat adjust = 0;

        for(int i = (section - 1); i >= 0; i--){
            if([self.hiddenSections containsObject:[NSNumber numberWithInt:i]]){
                adjust = adjust + 2;
            }
            else {
                break;
            }
        }

        if(adjust > 0)
        {                
            if(height == -1){
                height = self.tableView.sectionHeaderHeight;
            }

            height = height - adjust;

            if(height < 1){
                height = 1;
            }
        }
    }

    return height;
}

-(CGFloat)tableView:(UITableView *)tableView heightForFooterInSection:(NSInteger)section 
{   
    if([self.hiddenSections containsObject:[NSNumber numberWithInt:section]]){
        return 1;
    }
    return [super tableView:tableView heightForFooterInSection:section];
}

次に、非表示にする特定の行がある場合は、numberOfRowsInSectionとcellForRowAtIndexPathで返される行を調整できます。この例では、3つの行があるセクションがあり、3つは空で、削除する必要があります。

- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
    NSInteger rows = [super tableView:tableView numberOfRowsInSection:section];

    if(self.organization != nil){
        if(section == 5){ // Contact
            if([self.organization objectForKey:@"Phone"] == [NSNull null]){     
                rows--;
            }

            if([self.organization objectForKey:@"Email"] == [NSNull null]){     
                rows--;
            }

            if([self.organization objectForKey:@"City"] == [NSNull null]){     
                rows--;
            }
        }
    }

    return rows;
}

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{    
    return [super tableView:tableView cellForRowAtIndexPath:[self offsetIndexPath:indexPath]];
}

このoffsetIndexPathを使用して、行を条件付きで削除する行のindexPathを計算します。セクションのみを非表示にする場合は不要

- (NSIndexPath *)offsetIndexPath:(NSIndexPath*)indexPath
{
    int row = indexPath.row;

    if(self.organization != nil){
        if(indexPath.section == 5){
            // Adjust row to return based on which rows before are hidden
            if(indexPath.row == 0 && [self.organization objectForKey:@"Phone"] == [NSNull null] && [self.organization objectForKey:@"Email"] != [NSNull null]){     
                row++;
            }
            else if(indexPath.row == 0 && [self.organization objectForKey:@"Phone"] == [NSNull null] && [self.organization objectForKey:@"Address"] != [NSNull null]){     
                row = row + 2;
            }
            else if(indexPath.row == 1 && [self.organization objectForKey:@"Phone"] != [NSNull null] && [self.organization objectForKey:@"Email"] == [NSNull null]){     
                row++;
            }
            else if(indexPath.row == 1 && [self.organization objectForKey:@"Phone"] == [NSNull null] && [self.organization objectForKey:@"Email"] != [NSNull null]){     
                row++;
            }
        }
    }

    NSIndexPath *offsetPath = [NSIndexPath indexPathForRow:row inSection:indexPath.section];

    return offsetPath;
}

オーバーライドするメソッドはたくさんありますが、このアプローチについて私が気に入っているのは、再利用できることです。hiddenSections配列を設定して追加すると、正しいセクションが非表示になります。行を非表示にするのは少しトリッキーですが、可能です。グループ化されたUITableViewを使用している場合、境界線が正しく描画されないため、非表示にする行の高さを0に設定することはできません。


1
代わりにおそらく使用NSMutableSethiddenSectionsます。主にメンバーシップをテストしているので、はるかに高速です。
pixelfreak

いい答えです、オースティン。私はその回答に賛成票を投じ、将来これを私のプロジェクトの参照として使用します。pixelfreakはNSMutableSetforの使用についても優れhiddenSectionsていますが、回答のポイントは、どのタイプのデータ構造を使用するかについて、nit-pickyより概念的であると理解しています。
BigSauce 2012

10

結局のところ、静的なUITableViewのセルを非表示にして、アニメーションで表示できます。そして、それを達成することはそれほど難しくありません。

デモプロジェクト

デモプロジェクトビデオ

要旨:

  1. Use tableView:heightForRowAtIndexPath: ある状態に基づいてセルの高さを動的に指定します。
  2. 状態が変わると、呼び出しによってセルの表示/非表示をアニメーション化します tableView.beginUpdates();tableView.endUpdates()
  3. tableView.cellForRowAtIndexPath:内部に電話しないでくださいtableView:heightForRowAtIndexPath:。キャッシュされたindexPathを使用して、セルを区別します。
  4. セルを非表示にしないでください。代わりに、Xcodeの「Clip Subviews」プロパティを設定します。
  5. プレーンなどではなくカスタムセルを使用して、素敵な非表示アニメーションを取得します。また、セルの高さ== 0の場合の自動レイアウトを正しく処理します。

私のブログの詳細情報(ロシア語)


1
この点は私にとって重要でした。「セルを非表示にしないでください。代わりにXcodeで「Clip Subviews」プロパティを設定してください。」
バルコット2015

8

はい、確かにそれは可能ですが、現在同じ問題に取り組んでいます。セルを非表示にして、すべてが正常に機能するようになりましたが、現在、アニメーションをきれいに表示することはできません。これが私が見つけたものです:

最初のセクションの最初の行のON / OFFスイッチの状態に基づいて行を非表示にしています。スイッチがオンの場合、同じセクションのその下に1行あり、それ以外の場合は2つの異なる行があります。

スイッチが切り替えられたときに呼び出されるセレクターがあり、どの状態にあるかを示す変数を設定します。次に、次を呼び出します。

[[self tableView] reloadData];

tableView:willDisplayCell:forRowAtIndexPath:関数をオーバーライドし、セルを非表示にすることになっている場合は、次のようにします。

[cell setHidden:YES];

セルとその内容は非表示になりますが、セルが占めるスペースは削除されません。

スペースを削除するには、tableView:heightForRowAtIndexPath:関数をオーバーライドし、非表示にする必要がある行に0を返します。

また、tableView:numberOfRowsInSection:をオーバーライドして、そのセクションの行数を返す必要もあります。テーブルがグループ化されたスタイルの場合、丸い角が正しいセルで発生するように、ここで奇妙なことを行う必要があります。私の静的テーブルには、セクションのセルの完全なセットがあるため、オプションを含む最初のセルがあり、次にON状態オプション用の1つのセルとOFF状態オプション用の2つのセル、合計4つのセルがあります。オプションがオンの場合、4を返す必要があります。これには非表示のオプションが含まれるため、表示される最後のオプションには丸いボックスがあります。オプションがオフの場合、最後の2つのオプションは表示されないので、2を返します。これはすべて不格好な感じです。これがあまり明確でない場合は申し訳ありませんが、説明するのが難しいです。セットアップを説明するために、これはIBのテーブルセクションの構成です。

  • 行0:ON / OFFスイッチ付きのオプション
  • 行1:オプションがオンのときに表示されます
  • 行2:オプションがオフのときに表示されます
  • 行3:オプションがオフのときに表示されます

したがって、オプションがONの場合、テーブルは次の2つの行を報告します。

  • 行0:ON / OFFスイッチ付きのオプション
  • 行1:オプションがオンのときに表示されます

オプションがオフの場合、テーブルは次の4つの行を報告します。

  • 行0:ON / OFFスイッチ付きのオプション
  • 行1:オプションがオンのときに表示されます
  • 行2:オプションがオフのときに表示されます
  • 行3:オプションがオフのときに表示されます

このアプローチは、いくつかの理由で正しくないと思います。これまでのところ、これまでの実験で得た限りです。そのため、より良い方法を見つけた場合は、お知らせください。これまでに確認した問題は次のとおりです。

  • 行数が基になるデータに含まれていると思われる数と異なることをテーブルに伝えるのは間違っています。

  • 変化をアニメーション化できないようです。reloadDataの代わりにtableView:reloadSections:withRowAnimation:を使用してみましたが、結果が意味をなさないようですが、まだこれを機能させようとしています。現在発生しているように見えるのは、tableViewが正しい行を更新しないため、表示されるべき非表示のままになり、最初の行の下に空白が残ることです。これは、基礎となるデータに関する最初の点に関連していると思います。

うまくいけば、誰かが別の方法を提案したり、おそらくアニメーションを拡張する方法を提案したりできるでしょう。関数へのハイパーリンクがないことをお詫びし、ハイパーリンクを挿入しましたが、私はかなり新しいユーザーなので、スパムフィルターによって拒否されました。


[[self tableView] reloadData];セルを非表示にした後でもう一度電話をかける必要があると確信しています
Shmidt

これを復活させて申し訳ありませんが、UITableViewControllerをサブクラス化し、静的セルでどのように使用できましたか?Xcodeは私をさせません。
Dany Joumaa

Nessup、UITableViewをサブクラス化する必要はありません。ストーリーボードでTableViewControllerを選択し、TableViewをクリックします。これで、動的/静的セルを選択できます。
2012年

1
静的セルをアニメーション表示する方法を非表示/表示するソリューションを見つけました。静的セルを作成するにはreturn [super tableView:tableView cellForRowAtIndexPath:indexPath];UITableViewControllerサブクラスを呼び出すだけです。インデックスパスには静的なインデックスが付けられます-動的ではありません...
k06a

8

Justasの答えによると、しかしSwift 4の場合:

override func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
    let cell = super.tableView(tableView, cellForRowAt: indexPath)

    if cell == self.cellYouWantToHide {
        return 0
    }

    return super.tableView(tableView, heightForRowAt: indexPath)
}

1
tableView.reloadRows(at:, with:)行がすでに表示されているときに高さを変更した場合、セルを更新する必要がある場合があります。
Frost-Lee

5

さて、いくつか試した後、私は一般的ではない答えを持っています。「isHidden」または「hidden」変数を使用して、このセルを非表示にする必要があるかどうかを確認しています。

  1. ビューコントローラーにIBOutletを作成します。 @IBOutlet weak var myCell: UITableViewCell!

  2. myCellカスタム関数のを更新します。たとえば、viewDidLoadに追加できます。

override func viewDidLoad() { super.viewDidLoad() self.myCell.isHidden = true }

  1. あなたのデリゲートメソッドで:

override func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat { let cell = super.tableView(tableView, cellForRowAt: indexPath) guard !cell.isHidden else { return 0 } return super.tableView(tableView, heightForRowAt: indexPath) }

これにより、デリゲートメソッドのロジックが削減され、ビジネス要件に集中するだけで済みます。


4

セルの非表示/表示、rowHeightの変更、または自動レイアウト制約による混乱は、自動レイアウトの問題が原因で機能しませんでした。コードが耐えられなくなった。

単純な静的テーブルの場合、私にとって最も効果的だったのは次のとおりです。

  1. 静的テーブルのすべてのセルにアウトレットを作成します
  2. 表示するセルの出口のみを含む配列を作成します
  3. cellForRowAtIndexPathをオーバーライドして、配列からセルを返します
  4. numberOfRowsInSectionをオーバーライドして、配列の数を返します
  5. その配列に含まれる必要があるセルを決定するメソッドを実装し、必要に応じてそのメソッドを呼び出してから、reloadDataを呼び出します。

これが私のテーブルビューコントローラの例です。

@IBOutlet weak var titleCell: UITableViewCell!
@IBOutlet weak var nagCell: UITableViewCell!
@IBOutlet weak var categoryCell: UITableViewCell!

var cellsToShow: [UITableViewCell] = []

override func viewDidLoad() {
    super.viewDidLoad()
    determinCellsToShow()
}

func determinCellsToShow() {
    if detail!.duration.type != nil {
        cellsToShow = [titleCell, nagCell, categoryCell]
    }
    else {
        cellsToShow = [titleCell,  categoryCell]
    }
}

override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
    return cellsToShow[indexPath.row]
}

override func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
    return cellsToShow.count
}

これは5年後でもうまくいきました!どうもありがとうございます。
Schrockwell

2020年、これはこれに対する最大の解決策です。ハックは必要ありません。
mdonati

3

シンプルなiOS 11およびIB /ストーリーボード互換の方法

iOS 11の場合、モハメド・サレの回答の修正版が最もよく機能し、Appleのドキュメントに基づいていくつかの改良点があることがわかりました。うまくアニメーション化し、醜いハッキングやハードコードされた値を回避し、すでにInterface Builderで設定されている行の高さ使用します。

基本的な概念は、非表示の行の行の高さを0に設定することです。次に、を使用tableView.performBatchUpdatesして、一貫して機能するアニメーションをトリガーします。

セルの高さを設定する

override func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
    if indexPath == indexPathOfHiddenCell {
        if cellIsHidden {
            return 0
        }
    }
    // Calling super will use the height set in your storyboard, avoiding hardcoded values
    return super.tableView(tableView, heightForRowAt: indexPath)
}

確認する必要がcellIsHiddenありindexPathOfHiddenCell、ユースケースに適切に設定されます。私のコードでは、それらはテーブルビューコントローラーのプロパティです。

セルを切り替える

可視性を制御するメソッド(ボタンアクションまたはのようなdidSelectRow)では、performBatchUpdatesブロック内のcellIsHidden状態を切り替えます。

tableView.performBatchUpdates({
                // Use self to capture for block
                self.cellIsHidden = !self.cellIsHidden 
            }, completion: nil)

AppleはperformBatchUpdatesbeginUpdatesendUpdates可能な場合はいつでも/を推奨しています。


1

静的テーブルでセルをアニメーション化するための解決策を見つけました。

// Class for wrapping Objective-C block
typedef BOOL (^HidableCellVisibilityFunctor)();
@interface BlockExecutor : NSObject
@property (strong,nonatomic) HidableCellVisibilityFunctor block;
+ (BlockExecutor*)executorWithBlock:(HidableCellVisibilityFunctor)block;
@end
@implementation BlockExecutor
@synthesize block = _block;
+ (BlockExecutor*)executorWithBlock:(HidableCellVisibilityFunctor)block
{
    BlockExecutor * executor = [[BlockExecutor alloc] init];
    executor.block = block;
    return executor;
}
@end

追加の辞書は1つだけ必要です。

@interface MyTableViewController ()
@property (nonatomic) NSMutableDictionary * hidableCellsDict;
@property (weak, nonatomic) IBOutlet UISwitch * birthdaySwitch;
@end

そしてMyTableViewControllerの実装を見てください。indexPathを表示インデックスと非表示インデックスの間で変換するには、2つのメソッドが必要です...

- (NSIndexPath*)recoverIndexPath:(NSIndexPath *)indexPath
{
    int rowDelta = 0;
    for (NSIndexPath * ip in [[self.hidableCellsDict allKeys] sortedArrayUsingSelector:@selector(compare:)])
    {
        BlockExecutor * executor = [self.hidableCellsDict objectForKey:ip];
        if (ip.section == indexPath.section
            && ip.row <= indexPath.row + rowDelta
            && !executor.block())
        {
            rowDelta++;
        }
    }
    return [NSIndexPath indexPathForRow:indexPath.row+rowDelta inSection:indexPath.section];
}

- (NSIndexPath*)mapToNewIndexPath:(NSIndexPath *)indexPath
{
    int rowDelta = 0;
    for (NSIndexPath * ip in [[self.hidableCellsDict allKeys] sortedArrayUsingSelector:@selector(compare:)])
    {
        BlockExecutor * executor = [self.hidableCellsDict objectForKey:ip];
        if (ip.section == indexPath.section
            && ip.row < indexPath.row - rowDelta
            && !executor.block())
        {
            rowDelta++;
        }
    }
    return [NSIndexPath indexPathForRow:indexPath.row-rowDelta inSection:indexPath.section];
}

UISwitch値の1つのIBActionが変化します:

- (IBAction)birthdaySwitchChanged:(id)sender
{
    NSIndexPath * indexPath = [self mapToNewIndexPath:[NSIndexPath indexPathForRow:1 inSection:1]];
    if (self.birthdaySwitch.on)
        [self.tableView insertRowsAtIndexPaths:[NSArray arrayWithObject:indexPath] withRowAnimation:UITableViewRowAnimationAutomatic];
    else
        [self.tableView deleteRowsAtIndexPaths:[NSArray arrayWithObject:indexPath] withRowAnimation:UITableViewRowAnimationAutomatic];
}

いくつかのUITableViewDataSourceおよびUITableViewDelegateメソッド:

- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
    int numberOfRows = [super tableView:tableView numberOfRowsInSection:section];
    for (NSIndexPath * indexPath in [self.hidableCellsDict allKeys])
        if (indexPath.section == section)
        {
            BlockExecutor * executor = [self.hidableCellsDict objectForKey:indexPath];
            numberOfRows -= (executor.block()?0:1);
        }
    return numberOfRows;
}

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
    indexPath = [self recoverIndexPath:indexPath];
    return [super tableView:tableView cellForRowAtIndexPath:indexPath];
}

- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath
{
    indexPath = [self recoverIndexPath:indexPath];
    return [super tableView:tableView heightForRowAtIndexPath:indexPath];
}

- (void)viewDidLoad
{
    [super viewDidLoad];

    // initializing dictionary
    self.hidableCellsDict = [NSMutableDictionary dictionary];
    [self.hidableCellsDict setObject:[BlockExecutor executorWithBlock:^(){return self.birthdaySwitch.on;}] forKey:[NSIndexPath indexPathForRow:1 inSection:1]];
}

- (void)viewDidUnload
{
    [self setBirthdaySwitch:nil];
    [super viewDidUnload];
}

@end

1

迅速な回答:

TableViewControllerに次のメソッドを追加します。

override func tableView(tableView: UITableView, heightForRowAtIndexPath indexPath: NSIndexPath) -> CGFloat {
    return indexPathOfCellYouWantToHide == indexPath ? 0 : super.tableView(tableView, heightForRowAtIndexPath: indexPath)
}

非表示にしたいセルをtableViewが描画しようとした場合、上記のメソッドにより高さが0ptに設定されるため、それは表示されません。それ以外は変更されません。

その点に注意してください indexPathOfCellYouWantToHideいつでも変更できることに :)


1

> Swift 2.2では、いくつかの答えをここにまとめました。

ストーリーボードからアウトレットを作成して、staticCellにリンクします。

@IBOutlet weak var updateStaticCell: UITableViewCell!

override func viewDidLoad() {
    ...
    updateStaticCell.hidden = true
}

override func tableView(tableView: UITableView, heightForRowAtIndexPath indexPath: NSIndexPath) -> CGFloat {
    if indexPath.row == 0 {
        return 0
    } else {
        return super.tableView(tableView, heightForRowAtIndexPath: indexPath)
    }
}

最初のセルを非表示にしたいので、上記のように高さを0に設定します。


1

スウィフト4:

override func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
    var height = super.tableView(tableView, heightForRowAt: indexPath)
    if (indexPath.row == HIDDENROW) {
        height = 0.0
    }
    return height
}

0

テーブルビューの一番下にあるセルを非表示にする最も簡単なシナリオでは、セルを非表示にした後でtableViewのcontentInsetを調整できます。

- (void)adjustBottomInsetForHiddenSections:(NSInteger)numberOfHiddenSections
{
    CGFloat bottomInset = numberOfHiddenSections * 44.0; // or any other 'magic number
    self.tableView.contentInset = UIEdgeInsetsMake(self.tableView.contentInset.top, self.tableView.contentInset.left, -bottomInset, self.tableView.contentInset.right);
}


0

k06a(https://github.com/k06a/ABStaticTableViewController)からのソリューションは、セルのヘッダーとフッターを含むセクション全体を非表示にするため、より優れています。このソリューション(https://github.com/peterpaulis/StaticDataTableViewController)は、フッター以外のすべてを非表示にします。

編集

でフッターを非表示にする場合は、解決策を見つけましたStaticDataTableViewController。これはStaticTableViewController.mファイルにコピーする必要があるものです:

- (NSString *)tableView:(UITableView *)tableView titleForFooterInSection:(NSInteger)section {
    if ([tableView.dataSource tableView:tableView numberOfRowsInSection:section] == 0) {
        return nil;
    } else {
        return [super tableView:tableView titleForFooterInSection:section];
    }
}

- (CGFloat)tableView:(UITableView *)tableView heightForFooterInSection:(NSInteger)section {

    CGFloat height = [super tableView:tableView heightForFooterInSection:section];

    if (self.originalTable == nil) {
        return height;
    }

    if (!self.hideSectionsWithHiddenRows) {
        return height;
    }

    OriginalSection * os = self.originalTable.sections[section];
    if ([os numberOfVissibleRows] == 0) {
       //return 0;
        return CGFLOAT_MIN;
    } else {
        return height;
    }

    //return 0;
    return CGFLOAT_MIN;
}

0

きっとできます。最初に、表示するセルのtableViewの数に戻り、次に呼び出しsuperてストーリーボードから特定のセルを取得し、tableViewに返します。

override func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
    return self.mode.numberOfCells()
}

override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
    let cell = super.tableView(tableView, cellForRowAtIndexPath: self.mode.indexPathForIndexPath(indexPath))

    return cell
}

あなたの細胞が異なる高さを持っている場合もそれを返します:

override func tableView(tableView: UITableView, heightForRowAtIndexPath indexPath: NSIndexPath) -> CGFloat {
    return super.tableView(tableView, heightForRowAtIndexPath: self.mode.indexPathForIndexPath(indexPath))
}

0

@Saleh Masumソリューションに加えて:

あなたが取得する場合、自動レイアウトエラーを、あなただけの制約を削除することができますtableViewCell.contentView

スウィフト3:

override func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
    let tableViewCell = super.tableView(tableView, cellForRowAt: indexPath)

    if tableViewCell.isHidden == true
    {
        tableViewCell.contentView.removeConstraints(tableViewCell.contentView.constraints)
        return 0
    }
    else{
        return super.tableView(tableView, heightForRowAt: indexPath)
    }

}

このソリューションは、アプリのフローに依存します。同じView Controllerインスタンスでセルを表示/非表示にする場合は、制約が削除されるため、これ最良の選択ではない可能性があります


0

静的なセルとセクションさえも、ハックなしで動的に非表示にするより良い方法を得ました。

行の高さを0に設定すると行を非表示にすることができますが、すべての行を非表示にしても一部のスペースを保持するセクション全体を非表示にする場合は機能しません。

私のアプローチは、静的セルのセクション配列を構築することです。次に、テーブルビューのコンテンツはセクション配列によって駆動されます。

ここにいくつかのサンプルコードがあります:

var tableSections = [[UITableViewCell]]()

private func configTableSections() {
    // seciton A
    tableSections.append([self.cell1InSectionA, self.cell2InSectionA])

    // section B
    if shouldShowSectionB {
        tableSections.append([self.cell1InSectionB, self.cell2InSectionB])
    }

    // section C
    if shouldShowCell1InSectionC {
        tableSections.append([self.cell1InSectionC, self.cell2InSectionC, self.cell3InSectionC])
    } else {
        tableSections.append([self.cell2InSectionC, self.cell3InSectionC])
    }
}

func numberOfSections(in tableView: UITableView) -> Int {
    return tableSections.count
}

func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
    return tableSections[section].count
}

func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
    return tableSections[indexPath.section][indexPath.row]
}

このように、行とセクションの数を計算する厄介なコードを記述する必要なく、すべての構成コードをまとめることができます。そしてもちろん、いいえ0もはや高さはありません。

このコードは、メンテナンスも非常に簡単です。たとえば、さらにセルまたはセクションを追加/削除する場合などです。

同様に、セクションヘッダータイトル配列とセクションフッタータイトル配列を作成して、セクションタイトルを動的に構成できます。

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