[Swift] UITableViewの編集モードを制御して「削除のみ許可」,「ソートのみ許可」を実現する

More than 1 year has passed since last update.

UITableViewには編集モードというものがあります.
基本的な使い方は以下を参照していただければ理解できるかと思います.
UITableView の編集モードを利用してデータの削除や並び替えを行う

編集可能なCellの指定はUITableViewDataSourceのメソッドで行います.

// 1. 編集モードを許可するIndexPathの指定
func tableView(tableView: UITableView, canEditRowAtIndexPath indexPath: NSIndexPath) -> Bool
// 2. ソートを許可するIndexPathの指定
func tableView(tableView: UITableView, canMoveRowAtIndexPath indexPath: NSIndexPath) -> Bool

1.でtrueのCellは,削除が可能になり,2.のソートの可否指定が有効になります.
2.でtrueのCellは,ソートが可能になります.(1.でtrueの場合のみ)

つまり,

ソートのみ可能が標準でできない!!!

 
まあ利用頻度は少ないとは思いますが,強引にやってみたので共有します.

編集モード中の挙動

まず最初に,tableView.editing = trueにした時の,設定別の挙動について見てみます.

canEdit->false, canMove->false

スクリーンショット 2016-02-14 16.17.12.png
どちらもfalseのときは,当然何も起きません.

canEdit->true, canMove->false

スクリーンショット 2016-02-14 16.17.38.png
最初に説明したように,削除のみ可能となっています.

canEdit->false, canMove->true

スクリーンショット 2016-02-14 16.17.12.png
この場合は,tableView:canEditRowAtIndexPath:が許可されていないので,何も起きません

canEdit->true, canMove->true

スクリーンショット 2016-02-14 16.22.23.png
ソートを行うには両方をtrueにする必要がありますが,画像のように削除も可能となってしまいます.

編集モード中の画面構成

編集モード中は,(少し見づらいですが)下の画像のように,UITableViewCellContentViewが縮小され,両端にUITableViewCellEditControlというものが追加されています.

削除ボタンを隠す

実際,隠すとなると,方法はいくつかあるかもしれませんが,一番シンプルにできそうなものを紹介します.
どうするかといいますと,テーブルビューの幅を大きくしてやることで,削除ボタンを画面外におしやります.
それだけかよ,と思われた方,すみませんm(._.)m笑

幅をどのように変えるかですが,UITableViewの左余白のNSLayoutConstraintを調節してやります.
余談ですが,他の場合でもframeを調整するよりは,NSLayoutConstraintを調整した方がコード量も減りますし,調整しやすい場合が多いかと思います.(と,最近感じます)

UITableViewCellContentViewは,編集モードに入る時,(どちらもtrueで)両端が38px縮みます.
ですので,左余白のNSLayoutConstraintをその分マイナスしてやれば,うまく隠れてくれます.

テキストだけでは分かりづらいので,主要部分のコードを載せます.

// 編集タイプ
enum EditType {
  case None, All, Delete, Sort
}

var editType = EditType.None {
  willSet {
    self.tableView.editing = true
    self.leftConstraint.constant = 0
    if newValue == .None { self.tableView.editing = false }
    else if newValue == .Sort { self.leftConstraint.constant = -38 }
    self.tableView.reloadData()
  }
}

/**
 *  UITableView DataSource --------
 */
func tableView(tableView: UITableView, canEditRowAtIndexPath indexPath: NSIndexPath) -> Bool {
  switch self.editType {
    case .None : return false
    default : return true
  }
}

func tableView(tableView: UITableView, canMoveRowAtIndexPath indexPath: NSIndexPath) -> Bool {
  switch self.editType {
    case .None, .Delete : return false
    default : return true
  }
}

editTypeの値を変えてやることで,編集モードが切り替わるようになっています.

実行結果

上記コードで,self.editType = .Sortとした時の実行結果です.
スクリーンショット 2016-02-14 16.23.09.png
はい,うまく隠すことができましたね.

注意点

削除(ソート)をさせたくないCellがある場合は一工夫入ります.
TableView上の上2つを固定させたい時の例を示します.

func tableView(tableView: UITableView, canEditRowAtIndexPath indexPath: NSIndexPath) -> Bool {
  switch self.editType {
    case .None : return false
    case .Sort : return true  // ここ重要
    default :
      if indexPath.row < 2 { return false }
      else { return true }
  }
}

func tableView(tableView: UITableView, canMoveRowAtIndexPath indexPath: NSIndexPath) -> Bool {
  switch self.editType {
    case .None, .Delete : return false
    default :
      if indexPath.row < 2 { return false }
      else { return true }
  }

一見普通の処理に見えますが,コメント部分のように,.Sortのときはtrueを返すようにします.
今回の場合,ソートのみ可能とする場合にNSLayoutConstraintをいじっていますので,この処理を加えないと固定したCellが見切れてしまいます.

最後に

今回は,ソートのみ可能のTableViewを実装してみました.(制御という割にはベタな方法でしたが,,,)
Header, Footerがある場合は,フレームの調整が必要になりますが,シンプルに実装することができました.
今回のように,様々な状況に対応できるようなエンジニアになりたいですね.

それではよいiOSライフを!!!!

Sign up for free and join this conversation.
Sign Up
If you already have a Qiita account log in.