【Objective-C/Swift】iOS13対応にてUITableViewの「shouldIndentWhileEd
こういう人に向けて発信しています。
・編集モード中に左寄せしていた人
・iOS13対応をしている人
・下記UITableViewDelegateのデリゲートメソッドを使用している人
//インテント調整
- (BOOL)tableView:(UITableView *)tableView shouldIndentWhileEditingRowAtIndexPath:(NSIndexPath *)indexPath{
//チェックマーク分の余白を詰める為にインテントは表示しない。
return NO;
}
iOS12以前では編集モードで出てくるチェックボタンを消したい場合は
冒頭に貼りましたコードなどで対応する必要がありました。
そうすればインデント(左からの余白)が無しになり、
詰められるといった算段です。
しかしながら、iOS13でiOSシミュレータ上・実機で確認してみると、
上記コードは全く動作していない事が分かりました。
参考画像
上記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