😸

【Objective-C/Swift】iOS13対応にてUITableViewの「shouldIndentWhileEd

2020/09/29に公開

こういう人に向けて発信しています。

・編集モード中に左寄せしていた人
・iOS13対応をしている人
・下記UITableViewDelegateのデリゲートメソッドを使用している人

//インテント調整
- (BOOL)tableView:(UITableView *)tableView shouldIndentWhileEditingRowAtIndexPath:(NSIndexPath *)indexPath{
      //チェックマーク分の余白を詰める為にインテントは表示しない。
      return NO;
}

iOS12以前では編集モードで出てくるチェックボタンを消したい場合は
冒頭に貼りましたコードなどで対応する必要がありました。

そうすればインデント(左からの余白)が無しになり、
詰められるといった算段です。

しかしながら、iOS13でiOSシミュレータ上・実機で確認してみると、
上記コードは全く動作していない事が分かりました。

参考画像
https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/551622/54f8ea86-b288-dabb-f86d-058592cd6542.png

上記iOSシミュレーターは下記のコードで動かしております。
つまり、インデントを調整するデリゲートメソッドも採用しているにも
関わらずインデントがNOになっておりません。

#import "ViewController.h"

@interface ViewController ()<UITableViewDataSource,UITableViewDelegate>
@property (weak, nonatomic) IBOutlet UITableView *tableView;
@end

@implementation ViewController
- (void)viewDidLoad {
   [super viewDidLoad];
   self.tableView.delegate = self;
   self.tableView.dataSource = self;
   
       //編集モードを有効にする。
   [self.tableView setEditing:YES animated:YES];
   self.tableView.allowsMultipleSelectionDuringEditing = true;
}

//インテント調整
- (BOOL)tableView:(UITableView *)tableView shouldIndentWhileEditingRowAtIndexPath:(NSIndexPath *)indexPath{
      //チェックマーク分の余白を詰める為にインテントは表示しない。
      return NO;
}

//row = 行数を指定するデリゲートメソッド
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section{
   //必ずNSInteger型を返してあげている。
   return 30;
}

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath{
   //標準で用意されているTableViewを利用する場合。
   NSString *cellIdentifier = @"Cell";
   UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:cellIdentifier];
   
   if (!cell) {
       cell = [[UITableViewCell alloc]initWithStyle:UITableViewCellStyleDefault reuseIdentifier:cellIdentifier];
   }
   cell.textLabel.text = [NSString stringWithFormat:@"このセルは%ld番目のセルになります!", (long)indexPath.row];
   return cell;
}

@end

調査結果について

そもそもshouldIndentWhileEditingRowAtIndexPathでTweet検索して、
最新のツイートが2013年とかなのでニッチなデリゲートメソッドです。

なのでiOS13とか以前に関連する文献は一切見つかりませんでした。

特に公式で非推奨になるとアナウンスされたコードでも無いので、
不具合動作なのかなとも考えておりますが、
現時点で編集モード中インデントを無しにするというのは難しいと考えております。

対応策について
・編集モードは制御出来ないと考え使用しない。
・編集モードを自作する。

まずは仕様としては
・汎用性が高いようにセルを複数選択を想定する。
・セルを押下時は背景色を変えて、非選択時には背景色をデフォルトに。

上記仕様で考えて実装してみました。
Objective-C/Swift両方とも書いてみました。

Objective-C版

#import "ViewController.h"

@interface ViewController ()<UITableViewDataSource,UITableViewDelegate>
@property (weak, nonatomic) IBOutlet UITableView *tableView;
@property (strong,nonatomic) NSMutableArray<NSIndexPath *> *selectedIndexPathArray;

@end

@implementation ViewController


- (void)viewDidLoad {
   [super viewDidLoad];
   self.tableView.delegate = self;
   self.tableView.dataSource = self;
   self.selectedIndexPathArray = @[].mutableCopy;
}


- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section{
    return 30;
}


- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath{
   //標準で用意されているTableViewを利用する場合。
   NSString *cellIdentifier = @"Cell";
   UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:cellIdentifier];
   
   if (!cell) {
       cell = [[UITableViewCell alloc]initWithStyle:UITableViewCellStyleDefault reuseIdentifier:cellIdentifier];
   }
   cell.textLabel.text = [NSString stringWithFormat:@"このセルは%ld番目のセルになります!", (long)indexPath.row];
   return cell;
}


- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath{
   if([self.selectedIndexPathArray containsObject:indexPath]){
       [self.selectedIndexPathArray removeObject:indexPath];
   }else{
       [self.selectedIndexPathArray addObject:indexPath];
   }
   [self.tableView reloadData];

}



/**
@brief セル表示前の処理
*/
- (void)tableView:(UITableView *)tableView willDisplayCell:(UITableViewCell *)cell forRowAtIndexPath:(NSIndexPath *)indexPath{
   //セルのテキストが入っている場合は色を青にする
   if([self.selectedIndexPathArray containsObject:indexPath]){
       cell.backgroundColor = [UIColor lightGrayColor];
   }else{
       cell.backgroundColor = [UIColor clearColor];
   }
}

@end

Swift版

import UIKit

class ViewController: UIViewController, UITableViewDelegate, UITableViewDataSource  {
   @IBOutlet weak var tableView: UITableView!
   var selectedIndexPathArray : NSMutableArray = [] ;
   override func viewDidLoad() {
       super.viewDidLoad()
       // Do any additional setup after loading the view.
       self.tableView.dataSource = self;
       self.tableView.delegate = self;
   }

   func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
       return 30;
   }
   
   func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
       let cell = UITableViewCell(style: UITableViewCell.CellStyle.default, reuseIdentifier: "Cell")
       // セルに表示する値を設定する
       cell.textLabel!.text = indexPath.row.description
       return cell
   }
   
   func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
       if self.selectedIndexPathArray .contains(indexPath){
           self.selectedIndexPathArray.remove(indexPath)
       }else{
           self.selectedIndexPathArray.add(indexPath)
       }
       tableView.reloadData()
   }
   
   func tableView(_ tableView: UITableView, willDisplay cell: UITableViewCell, forRowAt indexPath: IndexPath) {
       if self.selectedIndexPathArray .contains(indexPath){
           cell.backgroundColor = .blue
       }else{
           cell.backgroundColor = .clear
       }
   }

}

簡単に解説するのであれば、
(1)選択されたNSIndexPathを管理する配列を用意する。
(2)押下時に配列にNSIndexPathを含むか判定し、
   含む場合は削除、含まない場合は追加する。
(3)セル表示前にセル自身のindexPathを判定し、
   含む場合は選択色、含まない場合は透過色(デフォルト)にする。

以上がロジックです。

Objective-C
NSArray *selectedIndexPaths = [self.tableView indexPathsForSelectedRows];

上記のようなコードで最後にTableViewの選択されている全てのセルを
取得すると思いますが、その場合は上記コードの配列をそのまま活用すればOKです。
(押下されたセルのみ、NSIndexPath型の配列なので)

本記事含め他の記事は「長時間1人で悩んで不安やストレスフルな方を解決したい」という一心で更新しております。少額でも構いませんのでサポートしていただけますと記事更新のモチベーションになりますので、御援助いただけますと助かります。

Discussion