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

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

ただいまの
回答率

90.35%

  • Swift

    7658questions

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

Section毎に折りたたみ可能としたtableView上で、LongPress先がsectionかCellか判別したい。

解決済

回答 1

投稿 編集

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

tyobigorou

score 547

セクションごとに折りたたみ機能をもたせたUITableViewUILongPressGestureRecognizerを追加して
ロングプレスされたpointがcellかSectionによって処理を分けたいのですが、どのようにしたら判別できるでしょうか?

tableViewがロングプレスされた際に、gestureのlocationからindexPathが取得できるのですが、Sectionをタップしても、ロングプレスしたSection直下のCellのindexpathしか取得できず(先頭のSectionだけは、ロングプレスすると、indexpathはnilと変換される。)、indexPathからロングプレスされたのがSectionかCellか判別することができません。senderに送られてくるlocation、view、subviewsあたりから取得できるcellとsectionを判別する基準があれば教えてください。

![イメージ説明](4e7e61c16a8d275ff1631e797fef4f11.gif)

 TableViewロングタップ時の処理

 // LongPressGestureRecognizerはstoryBoardで設置、Action接続済
 // longPressed leftTableView
    @IBAction func savedListCellLongPressed(_ sender: UILongPressGestureRecognizer) {
        if(sender.state == UIGestureRecognizerState.began) {

        } else if (sender.state == UIGestureRecognizerState.ended) {

            let point = sender.location(in: leftTableView)
            let indexPath = leftTableView.indexPathForRow(at: point)

            // ここでSectionとCellで処理を分けたい

            // gifでの表示用アラート
            let alert = UIAlertController(title: nil, message: nil, preferredStyle: .alert)
            alert.title = "point/indexPath"
            alert.message = "\(point)\n\(indexPath)"

            alert.addAction(
                UIAlertAction(title: "OK", style: .default, handler: nil ))
            self.present(alert, animated: true, completion: nil)

        }
    }

上記の方法ではtableViewに設置したUILongPressGestureRecognizerでcellとSectionの判別ができないため、コード上でSectionに別途UILongPressGestureRecognizerを追加したところ、
Sectionをロングプレスすると、10%くらいの頻度でSectionではなくCellのロングプレスが反応してしまい正常に機能させることができません。これは実装の仕方に問題があるのでしょうか?

 セクションとその折りたたみの実装

// titleOfSection
    func tableView(_ tableView: UITableView, viewForHeaderInSection section: Int) -> UIView? {
            let headerView = UIView(frame: CGRect(x: 0, y: 0, width: tableView.bounds.width, height: 30))
            headerView.backgroundColor = #colorLiteral(red: 0.1764705926, green: 0.4980392158, blue: 0.7568627596, alpha: 1)

            let headerLabel = UILabel(frame: CGRect(x: 5, y: 0, width: tableView.bounds.width - 5, height: 30))
            headerLabel.text = sectionNameStrArray[section][0]
            headerLabel.font = UIFont.boldSystemFont(ofSize: 15)
            headerLabel.textAlignment = .left
            headerLabel.textColor =  #colorLiteral(red: 1, green: 1, blue: 1, alpha: 1)

            // セクションに対応するtagを設定する
            headerView.tag = section

            // タップジェスチャを設定する
            headerView.addGestureRecognizer(
                UITapGestureRecognizer(target: self, action: #selector(self.tapHeader(gestureRecognizer:)))
            )

            // ここのaddGestureRecognizerを有効にすると一見キチンと動くように見えるが、cellとSectionどちらのRecognizerが反応するかが明白でない動きをする。
            /*
            // ロングタップジェスチャを設定する
            headerView.addGestureRecognizer(
                UILongPressGestureRecognizer(target: self, action: #selector(self.longTapHeader(gestureRecognizer:)))
            )
            */

            headerView.addSubview(headerLabel)
            return headerView
    }

    // heightOfSection
    func tableView(_ tableView: UITableView, heightForHeaderInSection section: Int) -> CGFloat {
            return 30
    }

// sectionHeaderTap
    @objc func tapHeader(gestureRecognizer: UITapGestureRecognizer) {
        guard let section = gestureRecognizer.view?.tag as Int! else { return }

        // sectionの表示状態を取得する
        let indicateStateOfSection = sectionNameStrArray[section][1]

        // sectionの表示状態を設定する
        if indicateStateOfSection == "T" {
            sectionNameStrArray[section][1] = "F"
        } else {
            sectionNameStrArray[section][1] = "T"
        }

        leftTableView.reloadSections(NSIndexSet(index: section) as IndexSet, with: .none)
    }


// sectionHeaderLongTap
    @objc func longTapHeader(gestureRecognizer: UITapGestureRecognizer) {
        if(gestureRecognizer.state == UIGestureRecognizerState.began) {

        } else if (gestureRecognizer.state == UIGestureRecognizerState.ended) {
             performSegue(withIdentifier: "goEditSection", sender: nil)
        }
     }
 }

 対処したことを追記

双方のLongPressGedtureRecognizerに.cancelsTouchesInView = falseを設定。(SB上ではチェックを外す)したところ、
誤動作(SectionLongPressしてもCellLongPressが動く)することが稀になる。

  • 気になる質問をクリップする

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

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

    クリップを取り消します

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

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

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

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

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

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

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

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

    質問の評価を下げる

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

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

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

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

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

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

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

    詳細な説明はこちら

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

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

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

回答 1

checkベストアンサー

+1

対症療法的でイマイチですが。

if let indexPath = tableView.indexPathForRow(at: point) {
    let rectCell = tableView.rectForRow(at: indexPath)
    if rectCell.contains(point) {
        print("cell", indexPath)
    } else {
        print("section", indexPath.section)
    }
} else {
    print("section 0")
}

投稿

編集

  • 回答の評価を上げる

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

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

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

  • 回答の評価を下げる

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

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

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

  • 2018/07/30 14:08 編集

    恐れ入ります。自分の用途には十分です。

    ここまで動くと、たたんであるときにsectionが判別できないのがもったいない気がしてきます。
    せっかく教えていただいたので、rectForHeaderあたりをつかってやってみます。

    キャンセル

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

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

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

  • Swift

    7658questions

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