UITableview:他の行ではなく一部の行の選択を無効にする方法


298

tableviewXMLから解析されたコンテンツをグループで表示しています。クリックイベントを無効にしたい(まったくクリックできないはずです)テーブルには2つのグループが含まれています。最初のグループのみの選択を無効にし、2番目のグループは無効にしたい。navigates私の管に2番目のグループの最初の行をクリックしplayer viewます。

特定のグループまたは行だけを選択可能にするにはどうすればよいですか?

- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath 
{
    if(indexPath.section!=0)
    if(indexPath.row==0)    

    [[UIApplication sharedApplication] openURL:[NSURL URLWithString:tubeUrl]];   
}

ありがとう。

回答:


499

あなたはこのコードを入れなければなりません cellForRowAtIndexPath

セルの選択プロパティを無効にするには:(セルをタップしている間)

cell.selectionStyle = UITableViewCellSelectionStyleNone;

セルを選択(タップ)できるようにするには:(セルをタップ)

// Default style
cell.selectionStyle = UITableViewCellSelectionStyleBlue;

// Gray style
cell.selectionStyle = UITableViewCellSelectionStyleGray;

が付いたセルでselectionStyle = UITableViewCellSelectionStyleNone;didSelectRowAtIndexPath、ユーザーがタッチしたときにUIが呼び出されることに注意してください。これを回避するには、以下の提案に従って設定します。

cell.userInteractionEnabled = NO;

代わりに。またcell.textLabel.enabled = NO;、アイテムをグレー表示に設定することもできます。


1
このメソッドは、スワイプして削除しようとするとバグを生成します。
Vive

116
これはハックです!それを行うには、以下の回答を使用します-willSelectRowAtIndexPathを使用してnilを返します!
Peter Stajger、

4
userInteractionEnabledのものは正しくありません。代わりにwillSelectRowAtIndexPathをフックしてください。
ジョニー2013年

23
iOS 6.0以降でtableView:shouldHighlightRowAtIndexPath:は、渡されたオブジェクトを強調表示するかどうかに基づいてUITableViewDelegateを返す新しいメソッドです。6.0以降でビルドする場合は、この新しいAPIを強くお勧めします。BOOLindexPath
cbowns 2013

3
Swiftでこれを実行していて問題が発生していて、ここで終了した場合はcell!.selectionStyle = .None、セルをアンラップするフォースを設定して、そのプロパティにアクセスできるようにする必要があります。
Marcos 14

371

行(または行のサブセット)を選択不可にする場合は、UITableViewDelegateメソッドを実装します-tableView:willSelectRowAtIndexPath:(TechZenでも言及されています)。を選択可能にするindexPath必要がない場合はを返し、それ以外の場合はを返します。デフォルトの選択動作を取得するには、メソッドに渡されたものを返すだけですが、別のを返すことで行選択を変更することもできます。nilindexPathindexPathdelegateindexPath

例:

- (NSIndexPath *)tableView:(UITableView *)tableView willSelectRowAtIndexPath:(NSIndexPath *)indexPath {
    // rows in section 0 should not be selectable
    if ( indexPath.section == 0 ) return nil;

    // first 3 rows in any section should not be selectable
    if ( indexPath.row <= 2 ) return nil;

    // By default, allow row to be selected
    return indexPath;
}

2
細部:あなたがメンター<= 2ではなく、<< 2。:)
JonasByström、2011年

23
これも正解ですが、cellForRowAtIndexPathでselectionStyleをUITableViewCellSelectionStyleNoneに設定する必要もあります。どうして?この選択スタイルがないと、セルは選択できませんが、タッチしても「選択した
とおり

4
承認された回答よりも多くの賛成票が必要です
user1244109

2
これが受け入れられた回答ではない主な理由は、受け入れられた回答の方が簡単だからです。テーブルが引き続きsetSelectedを呼び出すため、これは「最善の方法」ではありませんが、セルでは、視覚的には機能します。この回答はより多くの作業を必要としますが、セルでsetSelected:を呼び出すテーブルの予期しない結果を回避するために適切な方法です(@TooManyEduardosの提案も組み合わせる必要があります)。
Brian Sachetta、2015年

私はこの答えが好きですが、cellForRowAtIndexPathとwillSelectRowAtIndexPathのロジックを複製したくない場合は、willSelectRowAtIndexPathのcell.selectionStyle == noneを確認してnilを返します(以下の私の答えを参照)
Eric D'Souza

61

iOS 6以降では、

-tableView:shouldHighlightRowAtIndexPath:

に戻るNOと、選択の強調表示と、そのセルに接続されているストーリーボードトリガーセグエの両方が無効になります。

このメソッドは、タッチが行に来ると呼び出されます。NOそのメッセージに戻ると、選択プロセスが停止し、タッチを押している間、現在選択されている行の選択された外観が失われることはありません。

UITableViewDelegateプロトコルリファレンス


3
同意した。iOS 7以降では、これが推奨される方法です(実際には、iOS 8では、他の方法ではうまく
いき

これが一番の答えになるはずです。
Cameron E

16

上記の回答から、実際に問題に正しく対処したものはありません。その理由は、セルの選択を無効にしたいが、必ずしもセル内のサブビューを無効にしたくないからです。

私の場合、行の中央にUISwitchを表示しており、残りの行(空)の選択を無効にしたいが、スイッチは無効にしたくない!それを行う適切な方法は、メソッドにあります

- (void)tableView:(UITableView *)tableView willDisplayCell:(UITableViewCell *)cell forRowAtIndexPath:(NSIndexPath *)indexPath

フォームのステートメント

[cell setSelectionStyle:UITableViewCellSelectionStyleNone];

特定のセルの選択を無効にすると同時に、ユーザーがスイッチを操作して適切なセレクターを使用できるようにします。これは、誰かが

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath

セルを準備するだけで、UISwitchとの相互作用を許可しないメソッド。

さらに、メソッドを使用して

- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath

フォームのステートメントでセルの選択を解除するには

[tableView deselectRowAtIndexPath:indexPath animated:NO];

ユーザーがセルの元のcontentViewを押している間、行は選択されたままです。

ちょうど私の2セント。多くの人がこれが便利だと思うでしょう。


同意します。また、nilを返すwillSelectRowAtIndexPathと同じ問題が発生し、サブビューを選択できません。
jeffjv 2016

また、静的テーブルがある場合は、セルのInterface BuilderでSelectionをNoneに設定するだけで、選択を表示しないようにすることもできます。
jeffjv 2016

11

これらのデータソースメソッドを使用して選択範囲をトラップします。

 tableView:willSelectRowAtIndexPath: 
 tableView:didSelectRowAtIndexPath: 
 tableView:willDeselectRowAtIndexPath: 
 tableView:didDeselectRowAtIndexPath:

これらのメソッドでは、選択した行が選択可能にする行であるかどうかを確認します。ある場合はアクションを実行し、ない場合は何もしない。

残念ながら、1つのセクションのみの選択をオフにすることはできません。それはテーブル全体または何もありません。

ただし、テーブルセルselectionStyleプロパティをUITableViewCellSelectionStyleNone。これで選択が見えなくなります。セルをユーザーの視点から完全に不活性に見えるようにする上記の方法と組み合わせる。

Edit01:

一部の行のみが選択可能なテーブルがある場合、選択可能な行のセルを選択できない行と視覚的に区別することが重要です。シェブロンアクセサリボタンは、これを行うデフォルトの方法です。

ただし、どのような場合でも、ユーザーが行を選択しようとして、行が何もしないためにアプリが不正であると考えてはなりません。


これらの方法の使用方法を詳しく説明するか、サンプルプログラムのリンクを提供してください
Warrior

2
@Warrior:SDKがインストールされている場合は、Xcodeを開いて、に移動しHelp -> Developer documentation、それらのメソッド名を検索フィールドにコピーして、動作を確認します。開発者用ドキュメントには、サンプルコードも含まれています。
kennytm


9

cellForRowAtIndexPathメソッド内でセルの選択を無効にするには、次のようなことを行う必要があります。

[cell setSelectionStyle:UITableViewCellSelectionStyleNone];
[cell setUserInteractionEnabled:NO];

セルをグレー表示するには、tableView:WillDisplayCell:forRowAtIndexPathメソッド内に以下を配置します。

[cell setAlpha:0.5];

1つの方法では対話性を制御でき、もう1つの方法ではUIの外観を制御できます。


5

選択されている一部のセルのみを停止するには、以下を使用します。

cell.userInteractionEnabled = NO;

これにより、選択が妨げられるだけでなく、設定されているセルに対して呼び出されるtableView:didSelectRowAtIndexPath:も停止します。


1
奇妙なことが常に発生しますuserInteractionEnabled。1つのセル(より明確には、1つのindexPath)でNO に設定すると、他のいくつかのセルのユーザー操作が無効になります。userInteractionEnabledテーブルビューのセルで使用するたびにこれが発生する理由はわかりません。それは既知のバグですか、それとも何か問題がありますか?
Philip007 2013年

3
@ Philip007「NO」セルは再利用されていますか?その場合は、セルをデキューするときに必ず「YES」に設定する必要があります。
JosephH 2013年

1
なぜ「はい」に設定するのですか?NOにしたい(ユーザーの操作を禁止する)。典型的な例は、セルをデキューif [indexPath row] == 0NOtableView:cellForRowAtIndexPath:後に最初の行()のユーザーの操作をin に設定することです。通常、最初は問題なく動作します。次に、を何度か呼び出した後reloadData、突然5行目が許可されなくなったインタラクションになり、4行目がインタラクションされなくなります。いつ発生するかわかりません。全体がランダムに見えます。
Philip007 2013年

6
あなたはセルを再利用している場合はPhilip007 @、あなたがセルに「YES」にそれをリセットする必要がありますDOインタラクティブになりたいです。そうでない場合、インタラクティブにしたい行で「NO」セルが再利用されても、それは引き続き無効になります。ie:if [indexPath row] == 0) { set to NO } else { set to YES }
JosephH 2013年

5

このtableView:willDisplayCellメソッドを使用して、tableViewCellに対してあらゆる種類のカスタマイズを行うことができます。

- (void)tableView:(UITableView *)tableView willDisplayCell:(UITableViewCell *)cell forRowAtIndexPath:(NSIndexPath *)indexPath
{
     [cell setSelectionStyle:UITableViewCellSelectionStyleNone];
     [cell setUserInteractionEnabled:NO];

     if (indexPath.section == 1 && indexPath.row == 0)
     {
         [cell setSelectionStyle:UITableViewCellSelectionStyleGray];
         [cell setUserInteractionEnabled:YES];
     }
} 

この上のコードでは、ユーザーはtableViewの2番目のセクションの最初の行のみを選択できます。残りのすべての行は選択できません。ありがとう!



5

データモデルに基づく私のソリューション:

func tableView(_ tableView: UITableView, willSelectRowAt indexPath: IndexPath) -> IndexPath? {
    let rowDetails = viewModel.rowDetails(forIndexPath: indexPath)
    return rowDetails.enabled ? indexPath : nil
}

func tableView(_ tableView: UITableView, shouldHighlightRowAt indexPath: IndexPath) -> Bool {
    let rowDetails = viewModel.rowDetails(forIndexPath: indexPath)
    return rowDetails.enabled
}

5

Swift 4.0の場合、これでうまくいきます。これは、didSelectRowAtIndexPathメソッドのセルを無効にしますが、サブビューはクリック可能なままにします。

func tableView(_ tableView: UITableView, willSelectRowAt indexPath: IndexPath) -> IndexPath? {
         if (indexPath.row == clickableIndex ) { 
            return indexPath
         }else{
            return nil
        }
    }

または略してreturn indexPath.row == clickableIndex ? indexPath : nil、、コードを少しクリーンに保ちます;-)
マーク

1

これを使用して、セルが無効で選択できないよう表示します

cell.selectionStyle = UITableViewCellSelectionStyleNone;

重要:これは単なるスタイリングプロパティであり、実際にはセルを無効にするわけではないことに注意してください。これを行うにselectionStyleは、didSelectRowAtIndexPath:デリゲートの実装で確認する必要があります。

- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
    UITableViewCell *cell = [tableView cellForRowAtIndexPath:indexPath];
    if(cell.selectionStyle == UITableViewCellSelectionStyleNone) {
        return;
    }

    // do your cell selection handling here
}

1

私は上記のブライアン・チャパドスの答えが好きです。ただし、これは、cellForRowAtIndexPathとwillSelectRowAtIndexPathの両方でロジックが重複している可能性があることを意味します。ロジックを複製する代わりに、selectionStyleを確認するだけです。

- (NSIndexPath *)tableView:(UITableView *)tableView willSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
    UITableViewCell *cell = [tableView cellForRowAtIndexPath:indexPath];
    if (cell.selectionStyle == UITableViewCellSelectionStyleNone)
        return nil;

    else
        return indexPath;
}

1

静的テーブルと動的テーブルの両方で機能するので、これは便利です。選択を許可するセルにのみ開示インジケーターを設定します。

- (NSIndexPath *)tableView:(UITableView *)tableView willSelectRowAtIndexPath:(NSIndexPath *)indexPath {
    UITableViewCell *cell = [tableView cellForRowAtIndexPath:indexPath];
    if (cell.accessoryType != UITableViewCellAccessoryDisclosureIndicator) {
        return nil;
    }
    return indexPath;
}

1

コーディングなしのXcode 7では、次の操作を簡単に実行できます。

アウトラインビューで、[テーブルビューセル]を選択します。(セルは、テーブルビューコントローラーシーン>テーブルビューコントローラー>テーブルビューの下にネストされています。テーブルビューセルを表示するには、これらのオブジェクトを開示する必要がある場合があります)

属性インスペクタで、[選択]というラベルの付いたフィールドを見つけ、[なし]を選択します。 属性インスペクタ このオプションを使用すると、ユーザーがセルをタップしたときにセルが視覚的に強調表示されません。


0

シンプル

cell.userInteractionEnabled = YES;ナビゲートできる場合はセルに使用し、cell.userInteractionEnabled = NO;それ以外の場合は


1
これにより、セル内のアクセサリビューとの相互作用も防止されます。これは、望ましい動作ではない場合があります。
グレッグブラウン

0

tableView:willSelectRowAtIndexPath: テーブルのデータソースにメソッドのみを実装します。パスの行を強調表示する場合は、指定されたindexPathを返します。そうでない場合は、nilを返します。

私のアプリの例:

- (NSIndexPath *)tableView:(UITableView *)tableView
    willSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
    MySelectableObj* obj = [self objectAtPath:indexPath];
    if(obj==nil) return nil;
    return indexPath;
}

これの良い点はshouldPerformSegueWithIdentifier:sender:、完全を期すために上記のテストを繰り返していますが、上記のメソッドがnilを返す場合は呼び出されないことです。



0

ブライアンの答えに同意する

私が行った場合

cell.isUserInteractionEnabled = false 

その場合、セル内のサブビューはユーザーと対話しません。

他サイトでは、設定

cell.selectionStyle = .none

選択色を更新しないにもかかわらず、didSelectメソッドをトリガーします。

willSelectRowAtを使用して問題を解決しました。例:

func tableView(_ tableView: UITableView, willSelectRowAt indexPath: IndexPath) -> IndexPath? {

    if indexPath.section == 0{

        if indexPath.row == 0{
            return nil
        }

    }
    else if indexPath.section == 1{

        if indexPath.row == 0{
            return nil
        }

    }

    return indexPath

}

0

あなたからのアパートはtableView.allowsMultipleSelection = true、選択するときにセクションの残りのセルの選択を解除する必要があります:

func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
    if indexPath.section does not support multiple selection {
        // deselect the rest of cells
        tableView
            .indexPathsForSelectedRows?.compactMap { $0 }
            .filter { $0.section == indexPath.section && $0.row != indexPath.row }
            .forEach { tableView.deselectRow(at: $0, animated: true) }
    }
}

-1

Swift 3.0の場合、以下のコードを使用して、UITableViewセルへのユーザー操作を無効にすることができます

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