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

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

ただいまの
回答率

90.37%

  • Swift

    9168questions

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

  • Xcode

    5162questions

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

  • TableView

    147questions

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

Swift tableviewで選択したcellのチェックマークを維持する方法

解決済

回答 3

投稿 編集

  • 評価
  • クリップ 1
  • VIEW 2,240

kizahashi

score 4

 前提・実現したいこと

Xcodeにてアプリをつくっており、今は設定画面を作成しております。
以下のコードでtableviewのcellを選択した際にチェックマークを入れることは可能になったのですが
他のViewControllerなどに画面遷移をしてまた戻ってくるとチェックマークが消えてしまいます。
どのようなやり方でチェックマークを維持することができますか?

また特定のセルにチェックマークをつけるにはどうすればいいのでしょうか

tableViewControllerでDynamic Prototypeを使用しており遷移はNavigationContorollerで行なっています。

ご回答よろしくお願いいたします

 発生している問題・エラーメッセージ

なし

 該当のソースコード

コード

import UIKit

var selectSetting: String = ""

class SoundSelectTableViewController: UITableViewController {
    var soundArray = ["alerm1","alerm2","alerm3","alerm4"]
    override func viewDidLoad() {
        super.viewDidLoad()
        tableView.allowsMultipleSelection = false
        UserDefaults.standard.set(selectSetting, forKey: "selectSettingKey")


        // Uncomment the following line to preserve selection between presentations
        // self.clearsSelectionOnViewWillAppear = false

        // Uncomment the following line to display an Edit button in the navigation bar for this view controller.
        // self.navigationItem.rightBarButtonItem = self.editButtonItem
    }

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

    // MARK: - Table view data source

    override func numberOfSections(in tableView: UITableView) -> Int {
        // #warning Incomplete implementation, return the number of sections
        return 1
    }

    override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
        // #warning Incomplete implementation, return the number of rows
        return soundArray.count
    }


    override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
        let cell = tableView.dequeueReusableCell(withIdentifier: "soundSelectCell", for: indexPath)
        cell.textLabel?.text = soundArray[indexPath.row]
        // Configure the cell...
       // cell.accessoryType = .checkmark
       cell.selectionStyle = UITableViewCellSelectionStyle.none
        return cell
    }
    override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath){
        let cell = tableView.cellForRow(at:indexPath)
        // チェックマークを入れる
        cell?.accessoryType = .checkmark
        selectSetting = soundArray[indexPath.row]

    }
    override func tableView(_ tableView: UITableView, didDeselectRowAt indexPath: IndexPath) {
        let cell = tableView.cellForRow(at:indexPath)

        // チェックマークを外す
        cell?.accessoryType = .none
    }

    /*
    // Override to support conditional editing of the table view.
    override func tableView(_ tableView: UITableView, canEditRowAt indexPath: IndexPath) -> Bool {
        // Return false if you do not want the specified item to be editable.
        return true
    }
    */

    /*
    // Override to support editing the table view.
    override func tableView(_ tableView: UITableView, commit editingStyle: UITableViewCellEditingStyle, forRowAt indexPath: IndexPath) {
        if editingStyle == .delete {
            // Delete the row from the data source
            tableView.deleteRows(at: [indexPath], with: .fade)
        } else if editingStyle == .insert {
            // Create a new instance of the appropriate class, insert it into the array, and add a new row to the table view
        }    
    }
    */

    /*
    // Override to support rearranging the table view.
    override func tableView(_ tableView: UITableView, moveRowAt fromIndexPath: IndexPath, to: IndexPath) {

    }
    */

    /*
    // Override to support conditional rearranging of the table view.
    override func tableView(_ tableView: UITableView, canMoveRowAt indexPath: IndexPath) -> Bool {
        // Return false if you do not want the item to be re-orderable.
        return true
    }
    */

    /*
    // MARK: - Navigation

    // In a storyboard-based application, you will often want to do a little preparation before navigation
    override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
        // Get the new view controller using segue.destinationViewController.
        // Pass the selected object to the new view controller.
    }
    */
  • 気になる質問をクリップする

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

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

    クリップを取り消します

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

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

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

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

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

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

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

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

    質問の評価を下げる

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

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

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

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

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

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

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

    詳細な説明はこちら

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

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

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

質問への追記・修正、ベストアンサー選択の依頼

  • fuzzball

    2018/04/11 09:30

    コードは ``` で囲って下さい。

    キャンセル

回答 3

+2

cellは使い回されることを前提に設計して下さい。
cellの実体はデータ数分ではなく、画面表示に必要な分しか生成されず、
スクロールして画面からはみ出したcellは、別の新たに画面に表示されるcellに使い回されます。
tableView.dequeueReusableCell ← resuseable cell: 再使用可能なセル

従って、IndexPathに対応したチェックのOnOffを保持する変数を用意し、
tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath)
の中で、indexPathに対応したチェックのOnOff状態をcellに反映します。

投稿

  • 回答の評価を上げる

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

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

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

  • 回答の評価を下げる

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

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

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

  • 2018/04/12 13:39

    返信ありがとうございます。
    プロトタイプセルの中に配列が.rowになって入っていますがその配列の中の一つの要素のみのセルにチェックマークをつけるということです。

    cellに対してOnOff変更操作のやり方のがわかりません

    初心者なので変なこと言ってると思いますが
    tableView. soundSelectCell.cell[3]みたいな感じでcellを指定できればそれが一番いいのですが、この書き方では指定できません

    特定のcellだけを指定する方法が知りたいです。

    キャンセル

  • 2018/04/12 17:26

    > cellに対してOnOff変更操作のやり方のがわかりません

    tableView.dequeueReusableCell で生成されるcellは、UITableViewCellクラスであり、cell内に独自に追加したUIViewへの操作用funcやプロパティはありません。
    そこで、UITableViewCellを継承した、独自のセル(以後、CustomCell)を実装します。
    CustomCellに、チェックボックスを操作するためのfunc(IBAction func change(_ sender: Any)とか)もしくは、チェックボックスのプロパティ(IBOutlet checkBox: UIImageとか)を設定します。
    storyboard上のプロトタイプセルのCustom Classに上記のCustomCellを設定します。
    上記のfuncやプロパティとstoryboard上のUIViewとリンクを張ります。

    tableView.dequeueReusableCell で生成されるcellは、UITableViewCellクラスですが、上記によりCustomCellへの変換ができます。(let customCell = tableView.dequeueReusableCell(..略..) as CustomCell)
    あとは let customCellのfuncもしくはプロパティを操作します。

    > tableView. soundSelectCell.cell[3]みたいな感じでcellを指定できれば

    var soundArrayと同様に、cell用の配列(var cellArray: [CustomCell]とか)を用意します。
    func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath)において、
    tableView.dequeueReusableCell を使わずに、cellを生成します(let customCell = CustomCell())。
    cellArrayのindex.rowの位置に生成したcellを格納すれば、cellArray[index.row]で取り出せます。
    ただし、データ数分のcellを生成することになり、tableView.dequeueReusableCellを使用する時よりもメモリ使用量が増えます。

    キャンセル

  • 2018/04/15 11:52

    まだtableViewCellの扱いについての理解が浅いので勉強してきます。
    ご丁寧に返信ありがとうございました。

    キャンセル

checkベストアンサー

+1

>もとよりチェックをつけ直すというのが実装できません

チェックを付け直すというより、SoundSelectTableViewControllerが表示されたときに、
全てのセルにチェックされていない状態を設定しているのでこの機能をつかって特定セルだけに
チェックをつけてあげるのはどうでしょうか?

override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
        let cell = tableView.dequeueReusableCell(withIdentifier: "soundSelectCell", for: indexPath)
        cell.textLabel?.text = soundArray[indexPath.row]
       cell.selectionStyle = UITableViewCellSelectionStyle.none
        return cell
}


let Cell の部分で全てのセルを指定してチェックなし状態を適用しているので
selectSettingに値がある場合だけその値に対応するセルにチェックを付けるというふうに
if文で分岐してあげて特定CELLだけチェックを入れてあげればよいのではないでしょうか。

selectSettingにアラーム名を保持している場合は、indexOfで配列から対応するindexpathを取得して使います。
selectSettingにIndexPath.row(Int)を保持している場合はそのまま使えますね。 

tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) 
は自動実行なのでチェックを付けるタイミングは考えなくても不自由ないかと思います。

投稿

  • 回答の評価を上げる

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

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

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

  • 回答の評価を下げる

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

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

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

  • 2018/04/14 20:09

    チェックを外す部分が足らないみたいですね。
    ↓下記のdidSelectRowAtIndexPathの部分のif部分を参考にしてみてください。
    https://teratail.com/questions/15498

    キャンセル

  • 2018/04/15 11:49

    ご回答してくださった御三方何回も丁寧に返信していただき本当にありがとうございました。
    以下のように
    override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath){
    let cell = tableView.cellForRow(at:indexPath)
    tableView.allowsMultipleSelection = false
    // チェックマークを入れる
    if selectSetting == ""{}
    tableView.reloadData()


    didSelectRow内でチェックマークをつけた後にtableView reloadData()を付け加えたところチェックマークがちゃんと一つだけつくようになってくれました。

    まだtableViewについての理解が浅いと思ったので今回のご回答を参考にしてもっと理解できるよう頑張りたいと思います。

    みなさまほんと感謝です!m(_ _)mm(_ _)m

    キャンセル

  • 2018/04/15 12:03

    先ほどのコード間違えましたこちらが正しい方です
    override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath){
    let cell = tableView.cellForRow(at:indexPath)
    tableView.allowsMultipleSelection = false
    // チェックマークを入れる
    cell?.accessoryType = .checkmark
    tableView.reloadData()

    キャンセル

+1

UITableViewCellはスクロールされて画面から見えなくなると、これから見える別のCellとして再利用されますので、その際にチェックをつけたという情報はなくなってしまいます。 

例えば、
・チェックしている行(indexPath.row)を配列で保持する
・didSelectRowAt, didDeselectRowAtで対象行の配列への追加、削除を行う
・cellForRowAtで配列に含まれている行のチェックマークにチェックをつける

などいかがでしょうか?

投稿

  • 回答の評価を上げる

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

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

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

  • 回答の評価を下げる

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

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

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

  • 2018/04/12 16:55

    いえ質問しているのはこっちなのでいくら遅れようが構いませんよ
    ありがとうございます

    cell.accessoryType = trueとcellForRowAt内に書くと全てのセルにチェックマークがついてしまいますね
    引数のindexPathから特定のセルを判別できるということですがそれはどのように選択するのでしょうか?
    [indexPath.row]といつも書いているところに配列番号を入れてみたりいろいろ試行錯誤してみましたができませんでした
    そもそもindexPathというのは配列を示しているという認識で合っていますかね?

    キャンセル

  • 2018/04/12 17:12 編集

    cell.accessoryType = trueではなく、
    cell.accessoryType = .checkmarkとcell.accessoryType = .noneでできませんでしょうか?
    例えば、var selectSetting = [Int]()として、選択されているrowを保持しておき、
    if (selectSetting.contains(indexPath.row)) {
    cell.accessoryType = .checkmark
    } else {
    cell.accessoryType = .none
    }

    などでできませんでしょうか?

    キャンセル

  • 2018/04/15 11:56

    すみませんcell.accessoryType = trueはおかしかったです。
    ご丁寧に返信ありがとうございました。とても勉強になりました。

    キャンセル

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

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

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

  • Swift

    9168questions

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

  • Xcode

    5162questions

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

  • TableView

    147questions

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