質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

ただいまの
回答率

91.02%

  • Swift

    6082questions

    Swiftは、アップルのiOSおよびOS Xのためのプログラミング言語で、Objective-CやObjective-C++と共存することが意図されています

  • Xcode

    3503questions

    Xcodeはソフトウェア開発のための、Appleの統合開発環境です。Mac OSXに付随するかたちで配布されています。

  • iOS

    3457questions

    iOSとは、Apple製のスマートフォンであるiPhoneやタブレット端末のiPadに搭載しているオペレーションシステム(OS)です。その他にもiPod touch・Apple TVにも搭載されています。

  • TableView

    93questions

    TableView(UITableView)とは、リスト形式で表示するコントロールで、ほとんどのアプリに使用されています。画面を「行」に分けて管理し、一般的には各行をタップした際に詳細画面に移動します。

tableView チェックマークについて

解決済

回答 3

投稿 編集

  • 評価
  • クリップ 0
  • VIEW 351

haruka-t

score 47

 import UIKit

class ViewController: UIViewController, UITableViewDelegate,UITableViewDataSource {

  @IBOutlet weak var mytableView: UITableView!

  var kei = [String]()//["cell 追加 ボタン"]

  override func viewDidLoad() {
    super.viewDidLoad()

    mytableView.delegate = self
    mytableView.dataSource = self
   // trueで複数選択、falseで単一選択

  }


  @IBAction func addbtr(_ sender: Any) {


   let alert = UIAlertController(title: "タイトル", message: "メッセージ", preferredStyle: .alert)

      // OKボタンの設定
      let okAction = UIAlertAction(title: "OK", style: .default, handler: {
         (action:UIAlertAction!) -> Void in

         // OKを押した時入力されていたテキストを表示
         if let textFields = alert.textFields {

            // アラートに含まれるすべてのテキストフィールドを調べる
            for textField in textFields {
               self.kei.append(textField.text!) //insertは上に追加されappendは下に追加される
               self.kei.append("cell 追加 ボタン")
            }
            self.mytableView.reloadData()

         }
      })
      alert.addAction(okAction)

      // キャンセルボタンの設定
      let cancelAction = UIAlertAction(title: "Cancel", style: .cancel, handler: nil)
      alert.addAction(cancelAction)

      // テキストフィールドを追加
      alert.addTextField(configurationHandler: {(textField: UITextField!) -> Void in
         textField.placeholder = "テキスト"
      })


      alert.view.setNeedsLayout() // シミュレータの種類によっては、これがないと警告が発生

      // アラートを画面に表示
      self.present(alert, animated: true, completion: nil)

   }

  func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
    return kei.count
  }


   func tableView(tableView: UITableView, willSelectRowAtIndexPath indexPath: NSIndexPath) -> NSIndexPath? {

      switch indexPath.row {
      // 選択不可にしたい場合は"nil"を返す
      case 1:
         return indexPath;

      // 選択可にしたい場合は"indexPath"を返す
      default:
         return nil;
      }
   }

   func tableView(_ tableView: UITableView, willSelectRowAt indexPath: IndexPath) -> IndexPath? {
      if kei[indexPath.row] != "cell 追加 ボタン" {
         return nil
      }
      return indexPath
   }

   func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {

      let cell = tableView.dequeueReusableCell(withIdentifier: "cell", for: indexPath)
      //追加した内容に対して
      cell.textLabel?.text = kei[indexPath.row]
      cell.textLabel?.textColor = UIColor.red
      cell.backgroundColor = UIColor.black


      if kei[indexPath.row] != "cell 追加 ボタン" {
         cell.textLabel?.textColor = UIColor.black
         cell.backgroundColor = UIColor.yellow
         }
      if indexPath.row == 0 {
         cell.textLabel?.textColor = UIColor.black
         cell.backgroundColor = UIColor.white
      }

      return cell
   }

   /*if kei.count > (indexPath.row + 1)使うには  func tableView(_ tableView: UITableView, didSelectRowAtIndexPath: IndexPath){ を  func tableView(_ tableView: UITableView, didSelectRowAtIndexPath indexPath: IndexPath) -> IndexPath? {*/
   func tableView(_ tableView: UITableView, didSelectRowAtIndexPath indexPath: IndexPath) -> IndexPath? {

      let cell = tableView.cellForRow(at: indexPath)

     if cell?.textLabel?.text != "cell 追加 ボタン" {
      cell?.accessoryType = cell?.accessoryType == .checkmark ? .none : .checkmark
      tableView.deselectRow(at: indexPath, animated: true)
      return nil
     }else {
      let alert = UIAlertController(title: "タイトル", message: "メッセージ", preferredStyle: .alert)

    // OKボタンの設定
    let okAction = UIAlertAction(title: "OK", style: .default, handler: {
      (action:UIAlertAction!) -> Void in

      // OKを押した時入力されていたテキストを表示
      if let textFields = alert.textFields {

        // アラートに含まれるすべてのテキストフィールドを調べる
        for textField in textFields {
          self.kei.insert(textField.text!, at: indexPath.row)//indexPath.rowで1,2,3,4のような順になる
          //self.kei.insert(textField.text!, at:self.kei.count - 1)
        }
          self.mytableView.reloadData()

      }
    })
    alert.addAction(okAction)

    // キャンセルボタンの設定
    let cancelAction = UIAlertAction(title: "Cancel", style: .cancel, handler: nil)
    alert.addAction(cancelAction)

    // テキストフィールドを追加
    alert.addTextField(configurationHandler: {(textField: UITextField!) -> Void in
      textField.placeholder = "テキスト"
    })


    alert.view.setNeedsLayout() // シミュレータの種類によっては、これがないと警告が発生

    // アラートを画面に表示
    self.present(alert, animated: true, completion: nil)

      return indexPath
      }

  }


  //cellの削除について
  func tableView(_ tableView: UITableView, commit editingStyle: UITableViewCellEditingStyle, forRowAt indexPath: IndexPath) {
    if editingStyle == .delete {
      self.kei.remove(at: indexPath.row)
      tableView.deleteRows(at: [indexPath], with: .fade)
   }
  }

   func tableView(_ tableView: UITableView, editActionsForRowAt indexPath: IndexPath) -> [UITableViewRowAction]? {

      let delete = UITableViewRowAction(style: .normal, title: "削除") {ation, index in
         self.kei.remove(at: (indexPath.row))
         tableView.deleteRows(at: [indexPath], with: .fade)
   }
      delete.backgroundColor = .red

      let edit = UITableViewRowAction(style: .normal, title: "編集") { action, index in

         let alert = UIAlertController(title: "タイトル", message: "メッセージ", preferredStyle: .alert)

         // OKボタンの設定
         let okAction = UIAlertAction(title: "OK", style: .default, handler: {
            (action:UIAlertAction!) -> Void in

            // OKを押した時入力されていたテキストを表示
            if let textFields = alert.textFields {

               // アラートに含まれるすべてのテキストフィールドを調べる
               for textField in textFields {
                  self.kei[indexPath.row] = textField.text!
                  //self.kei.append(textField.text!)
               }
               self.mytableView.reloadData()

            }
         })
         alert.addAction(okAction)

         // キャンセルボタンの設定
         let cancelAction = UIAlertAction(title: "Cancel", style: .cancel, handler: nil)
         alert.addAction(cancelAction)

         // テキストフィールドを追加
         alert.addTextField(configurationHandler: {(textField: UITextField!) -> Void in
            textField.placeholder = "テキスト"
         })


         alert.view.setNeedsLayout() // シミュレータの種類によっては、これがないと警告が発生

         // アラートを画面に表示
         self.present(alert, animated: true, completion: nil)
         print("edit")
      }
      edit.backgroundColor = .orange

      return [delete,edit]
      }

  // trueを返すことでCellのアクションを許可しています
  func tableView(_ tableView: UITableView, canEditRowAt indexPath: IndexPath) -> Bool {

   if kei.count > (indexPath.row + 1) {
      return true
   }else{
    return false
  }
   }

  override func didReceiveMemoryWarning() {
    super.didReceiveMemoryWarning()
    // Dispose of any resources that can be recreated.
  }
}

やりたい事
[cell 追加 ボタン]とtitleのcell以外のcellをタップした時にチェックマークをつけたり、消したりできるようにしたいです

今出来ているところ
一応cellを追加する時にチェックマークが勝手につくように出来ました

困っているところ
cellが追加された時にはまだチェックマークがついてない状態にしたいです。
それとつけることは出来たのですがタップした時にチェックマークを消せない状態にいます。
elseで消す処理は書いているのですが反応してくれません。
それで下記のようにしてみればと考えたのですがcell追加時には確かにcellが追加されなくはなったのですがそしたら今度はcellにチェックマークがつかなくなりました

func didSelectRowAtIndexPathでこのようなコードを追加したところ[cell 追加 ボタン]だけcellが追加出来るようになりました

 let cell = tableView.cellForRow(at: indexPath)

      if cell!.accessoryType == .checkmark{
         cell!.accessoryType = .none
      }else{
         cell!.accessoryType = .checkmark
      }

追記
イメージ説明

@IBAction func addbtr(_ sender: Any) {
   self.kei.append(textField.text!) 
     self.kei.append("cell 追加 ボタン")

試したこと

    if cell?.textLabel?.text != "cell 追加 ボタン" && cell.textLabel?.text != "textField.text!" {

@IBAction func addbtr
のなかのself.kei.append(textField.text!) をcell.textLabel?.text != "title"に当てはめればおそらく私のやりたい事が出来ると思うんですけどtextField.text!の場合""に入れても"cell 追加 ボタン"のようにチェックがつかないようにならないです。

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

      let cell = tableView.cellForRow(at: indexPath)

      if indexPath.row == 0 {
         return nil
      }

     if cell?.textLabel?.text != "cell 追加 ボタン"{
      cell?.accessoryType = cell?.accessoryType == .checkmark ? .none : .checkmark
      tableView.deselectRow(at: indexPath, animated: true)
      return nil
  • 気になる質問をクリップする

    クリップした質問は、後からいつでもマイページで確認できます。

    またクリップした質問に回答があった際、通知やメールを受け取ることができます。

    クリップを取り消します

  • 良い質問の評価を上げる

    以下のような質問は評価を上げましょう

    • 質問内容が明確
    • 自分も答えを知りたい
    • 質問者以外のユーザにも役立つ

    評価が高い質問は、TOPページの「注目」タブのフィードに表示されやすくなります。

    質問の評価を上げたことを取り消します

  • 評価を下げられる数の上限に達しました

    評価を下げることができません

    • 1日5回まで評価を下げられます
    • 1日に1ユーザに対して2回まで評価を下げられます

    質問の評価を下げる

    teratailでは下記のような質問を「具体的に困っていることがない質問」、「サイトポリシーに違反する質問」と定義し、推奨していません。

    • プログラミングに関係のない質問
    • やってほしいことだけを記載した丸投げの質問
    • 問題・課題が含まれていない質問
    • 意図的に内容が抹消された質問
    • 広告と受け取られるような投稿

    評価が下がると、TOPページの「アクティブ」「注目」タブのフィードに表示されにくくなります。

    質問の評価を下げたことを取り消します

    この機能は開放されていません

    評価を下げる条件を満たしてません

    評価を下げる理由を選択してください

    詳細な説明はこちら

    上記に当てはまらず、質問内容が明確になっていない質問には「情報の追加・修正依頼」機能からコメントをしてください。

    質問の評価を下げる機能の利用条件

    この機能を利用するためには、以下の事項を行う必要があります。

回答 3

+2

 #1 チェックマークのON/OFF状態を保存する変数を用意する

例えばchecked[Bool]など。テキストを保存しているkey[]と同様のものです。

 #2 セルにチェックマークを付ける/消す

tableView(_:cellForRowAt:)の中に書きます。checked[]を見てON/OFFします。

 #3 チェックマークのON/OFF切り替え

tableView(_:didSelectRowAt:)の中ではON/OFFを切り替え(checked[]の書き換え)処理を書きます。checked[]を書き換えただけではセルの表示が変わりませんので、UITableViewのreloadRows(at:with:)などを使ってセルを更新します。

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

checkベストアンサー

+1

コードが全て載っていないと思うので想像ですが、以前の続きだとすると、
「cell 追加 ボタン」だけ反応するようにコードを書いていたと思うので、
willSelectRowAt での判定は行わず、 didSelectRowAt で判定を行うようにしてあげれば反応するようになります。

    if kei[indexPath.row] == "cell 追加" {
      return indexPath
    }

例えば、「cell 追加 ボタン」以外は accessoryType を変更して処理を返すようにすれば、他の処理は変更しないで実現できます。

    if cell?.textLabel?.text != "cell 追加 ボタン" {
      cell?.accessoryType = cell?.accessoryType == .checkmark ? .none : .checkmark
      tableView.deselectRow(at: indexPath, animated: true)
      return
    }

と書きましたが、 @fuzzball さんの指摘の通り、スクロール可能になるくらいデータを追加し、スクロールするとチェックマークがスクロールする度に付いたり消えたりします。なので、 @fuzzball さんの回答の通り、チェックマークを管理するデータ保存領域が必要になります。

もし、セルのタイトルとチェック状態を別々で管理するのが不自然だと感じたら、データ構造を追加する頃合いだと思います。 チェック可能な TableView を書いてみましたので参考にしてみてください。

titleの部分にチェックつけないようにしたい

画面キャプチャのように文字通り「title」のセルにはチェックをつけたくないだけでしたら、以下のように条件を論理積で繋げれば、どちらの条件も満たさないセルのみにチェックをつけることが可能になります。

    if cell?.textLabel?.text != "cell 追加 ボタン" && cell.textLabel?.text != "title" {

データ構造を採用するなら、プロパティに completable を追加して制御するのが自然かなと思います。
Add completable

以下の条件文で判定されるのは、「cell 追加 ボタン」「textField.text!」と言う文字列そのものと同じではないとなります。" で括ると Swift では String となり、その中に変数を書いても展開されません。

    if cell?.textLabel?.text != "cell 追加 ボタン" && cell.textLabel?.text != "textField.text!" {

入力したテキストと比較したいなら、データを格納している kei と比較することになるのですが、追記された説明から kei を対象にしたい訳ではないと読み取れます。下記のようにした場合は、セルに表示されている文字列= kei に格納されている文字列となる訳なので何もチェックできないでしょう。

    if cell?.textLabel?.text != "cell 追加 ボタン" && cell.textLabel?.text != kei[indexPath.row] {

なので、遡って、チェック可能なデータなのかプロパティを追加する必要があります。

投稿

編集

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2017/10/02 16:01

    willSelectRowAtの部分を消してコードを変更したら出来ました。
    それとなんですがtitleの部分にチェックつけないようにしたいのですが、そのために
    if cell?.textLabel?.text != "cell 追加 ボタン" {
    の部分を if cell?.textLabel?.text != "textField.text!" {
    としようとしたのですがtextFieldの場合だとエラーが出て"cell 追加 ボタン"のように出来ないのですがこの場合どうしたらいいのでしょうか?
    いろんな方法試して見たのですがどうしても出来ませんでした。
    一応if indexPath.row == 0 {  このようにすると一番最初のtitleだけチェックがつかなくなったのですがそれ以外のtitleはどうすればいいかわからない状態でいます。

    キャンセル

  • 2017/10/02 16:12

    @ykwsさん
    現在画面に表示されているセルに対して直接チェックマークをつけると、テーブルをスクロールした場合など、セルが再生成されたときにおかしくなると思います。

    キャンセル

  • 2017/10/03 15:11

    @haruka-t さん、回答を編集しました。参考にしてみてください。
    @fuzzball さん、指摘ありがとうございます。その通りですね

    キャンセル

  • 2017/10/03 23:36

    画像内のtitleは例としてあげたもので本当は[+]ボタンのテキストアラートで入力したものなのでself.kei.append(textField.text!)の部分を関連づけさせないといけないのですがそのやり方が分からないです。
    それで一応if cell?.textLabel?.text != "cell 追加 ボタン"を参考にif cell?.textLabel?.text != "textField.text!"にして見たのですがtextField.text!だと"cell 追加 ボタン"を真似ても関連させることが出来ませんでした。それでなんですがtextField.text!場合だとどのようにすればいいのか教えて頂けないのでしょうか?

    キャンセル

  • 2017/10/04 00:12

    データ構造を採用した場合の変更について追記しました。

    ただ、スクリーンショットのようなデータ構造が想像できないです。
    テキストアラートで入力したもの以外のセルはどうやって追加され、どこで管理されているのでしょうか?
    チェックをつけたいセルとつけたくないセルがあることはわかりましたが、それの区別をどうやってつけるのかがわからないです。プログラミングの話ではなく、日本語の話です。

    キャンセル

  • 2017/10/04 11:24

    質問に説明を追加しました。うまく説明出来なくお手数おかけしてすいません。それと質問に追加した説明を簡単に説明すると+ボタンで追加2つのセルにはチェックがつかずcell 追加 ボタン で追加したcellだけをチェックつけたり外せたりを出来るようになりたいです

    キャンセル

  • 2017/10/04 14:33

    回答に追記しました。説明を追加してもらいましたが、まだどのようなデータ構造を想定しているのかがわからないです。単純に一つの文字列の配列だけでは限界があるように思い、回答には構造体を利用したプロパティの導入を記載しています。

    キャンセル

  • 2017/10/04 17:31

    if indexPath.row == 0
    このようにすると最初の+ボタンで追加したcellだけはチェック出来ないようにしたのですが、やはりそれ以降に+ボタンで追加するcellはタップするとチェックがついちゃいました。
    なので@ykwsさんに教えて頂いた構造体を使った方法が最善の方法だと思うのですが構造体に関しては今の私の知識ではちょっと理解できないです。
    それとビルドして試して気づいたのですが+ボタンでcellを追加するとチェックマークがずれていくのですがこれって後に永続保存させる時にcore data かuser defalutsを使っても改善しない問題でしょうか?

    キャンセル

  • 2017/10/04 17:58

    indexPath.row == 0 は一番上のセルであると言う条件なので当然そうなります。
    チェックマークがずれる点は @fuzzball さんの指摘の通りなので、構造体が難しい場合は、そちらの回答にあるように表示用とは別にチェック用のデータ領域を用意する必要があります。

    本件において永続化は特に関係ないですが、表示用とチェック用のデータ領域をそれぞれ用意するのであれば、結果的に改善されるとは思います。

    キャンセル

+1

はじめまして。

UITableViewDelegateを定義して、didSelectRowAt を実装し、タップされたときに
該当のcellにチェックをつけるとよいとおもいます。

cellForRowAt では、 .none を設定しておき、タップしたときにチェックを付ける形です。

import UIKit

class ViewController: UIViewController , UITableViewDataSource, UITableViewDelegate{

~ 略 ~


    // Cell が選択された場合
    func tableView(_ table: UITableView,didSelectRowAt indexPath: IndexPath) {

        let cell = tableView.cellForRow(at:indexPath)

        // チェックマークを付ける
        cell?.accessoryType = .checkmark

    }

ご参考までに。

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2017/10/02 16:13

    >>cellForRowAt では、 .none を設定しておき
    それだと、テーブルをスクロールしたときなど、セルが再生成されたときにチェックマークが消えてしまいます。

    キャンセル

  • 2017/10/02 16:37

    なるほど、それでは対象の値をディクショナリに保存しておいてはいかがでしょうか?

    変数を用意
    var dicChk = [Int: Bool]()

    didSelectRowAt で
    let cell = tableView.cellForRow(at:indexPath)
    if dicChk[indexPath] == false{
    cell?.accessoryType = .checkmark
    dicChk[indexPath.row] = true
    }else{
    cell?.accessoryType = .none
    dicChk[indexPath.row] = false
    }


    cellForRowAt では、
    dicChk[indexPath.row].isEmpty であれば .none
    値が定義されていればその値にしたがって.none / .checkmark を
    設定すればよいとおもいます。

    キャンセル

15分調べてもわからないことは、teratailで質問しよう!

  • ただいまの回答率 91.02%
  • 質問をまとめることで、思考を整理して素早く解決
  • テンプレート機能で、簡単に質問をまとめられる

関連した質問

同じタグがついた質問を見る

  • Swift

    6082questions

    Swiftは、アップルのiOSおよびOS Xのためのプログラミング言語で、Objective-CやObjective-C++と共存することが意図されています

  • Xcode

    3503questions

    Xcodeはソフトウェア開発のための、Appleの統合開発環境です。Mac OSXに付随するかたちで配布されています。

  • iOS

    3457questions

    iOSとは、Apple製のスマートフォンであるiPhoneやタブレット端末のiPadに搭載しているオペレーションシステム(OS)です。その他にもiPod touch・Apple TVにも搭載されています。

  • TableView

    93questions

    TableView(UITableView)とは、リスト形式で表示するコントロールで、ほとんどのアプリに使用されています。画面を「行」に分けて管理し、一般的には各行をタップした際に詳細画面に移動します。