1
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

RxDataSourcesを用いたTableViewで特定の条件に該当するセルを編集不可にする方法

Last updated at Posted at 2023-12-16

記事の目的

RxDataSourcesを用いたUITableViewで、特定の条件に該当するセルを編集不可にするのに時間がかかったため、本記事でまとめておこうと思います。

実装

セルの編集可否は canEditRowAtIndexPath のクロージャー内で実装します。コードは以下の通りです。

self.dataSource = RxTableViewSectionedReloadDataSource<SectionOfCustomData>(
            configureCell: { (ds: TableViewSectionedDataSource<SectionOfCustomData>, tableView: UITableView, indexPath: IndexPath, model: CustomData) -> UITableViewCell in
                
                let cell = tableView.dequeueReusableCell(withIdentifier: "Cell", for: indexPath)
                cell.textLabel?.text = model.str
                return cell
            }, canEditRowAtIndexPath: { datasource, indexPath in
                
                let data = datasource.sectionModels[indexPath.section].items
                
                if data[indexPath.row].str == "zero" {
                    return false
                }
                return true
            }, canMoveRowAtIndexPath: { _, _ in
                return false
            }
        )

こちらのコードでは、data[indexPath.row].str == "zero" であるセルが編集不可となります。
画像.GIF




コード全体は以下の通りです。
なお、RxDataSourcesを用いてサンプルとなるTableViewを作成する部分の実装は、こちらのサイトのコードを参考にさせていただきました。

ViewController.swift
import UIKit
import RxSwift
import RxCocoa
import RxDataSources

class ViewController: UIViewController, UITableViewDelegate {
    
    @IBOutlet weak var tableView: UITableView!
    
    
    @IBAction func editButton(_ sender: UIButton) {
        self.tableView.setEditing(true, animated: true)
    }
    
    @IBAction func cancelButton(_ sender: UIButton) {
        self.tableView.setEditing(false, animated: true)
    }
    
    var dataSource: RxTableViewSectionedReloadDataSource<SectionOfCustomData>!
    
    let disposeBag = DisposeBag()
    
    override func viewDidLoad() {
        super.viewDidLoad()
        
        tableView.tableFooterView = UIView()
        
        tableView.rx.setDelegate(self).disposed(by: self.disposeBag)
        setupDataSource()
        bindModels()
    }
    
    override func viewWillAppear(_ animated: Bool) {
        super.viewWillAppear(animated)
        navigationController?.setNavigationBarHidden(false, animated: true)
        navigationController?.setToolbarHidden(false, animated: true)
    }
    
    func setupDataSource() {
        self.dataSource = RxTableViewSectionedReloadDataSource<SectionOfCustomData>(
            configureCell: { (ds: TableViewSectionedDataSource<SectionOfCustomData>, tableView: UITableView, indexPath: IndexPath, model: CustomData) -> UITableViewCell in
                
                let cell = tableView.dequeueReusableCell(withIdentifier: "Cell", for: indexPath)
                cell.textLabel?.text = model.str
                return cell
            }, canEditRowAtIndexPath: { datasource, indexPath in
                
                let data = datasource.sectionModels[indexPath.section].items
                
                if data[indexPath.row].str == "zero" {
                    return false
                }
                return true
            }, canMoveRowAtIndexPath: { _, _ in
                return false
            }
        )
        self.dataSource.titleForHeaderInSection = { ds, index in
            return ds.sectionModels[index].header
        }
    }
    
    func bindModels() {
        let sections = [
            SectionOfCustomData(header: "First section",
                                items: [CustomData(str: "zero"),
                                        CustomData(str: "one")]
                               ),
            SectionOfCustomData(header: "Second section",
                                items: [CustomData(str: "two"),
                                        CustomData(str: "zero"),
                                        CustomData(str: "three")]
                               )
        ]
        Observable.just(sections)
            .bind(to: tableView.rx.items(dataSource: self.dataSource))
            .disposed(by: self.disposeBag)
    }
}
SectionOfCustomData.swift
import Foundation
import RxDataSources

struct CustomData {
    var str: String
}

struct SectionOfCustomData {
    var header: String
    var items: [Item]
}

extension SectionOfCustomData: SectionModelType {
    typealias Item = CustomData

    init(original: SectionOfCustomData, items: [SectionOfCustomData.Item]) {
        self = original
        self.items = items
    }
}

注意点

上記のコードで、"zero" のセルを編集不可にできましたが、編集モード中に "zero" のセルをタップすることは可能なため、セルタップ時には選択済のセルとしてカウントされます。
そのため、上記コードを tableView.allowsMultipleSelectionDuringEditing = true で使用する場合、セル選択時の処理で tableView.indexPathsForSelectedRows から該当のセルのindexPath を取り除く処理が必要です。

1
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?