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

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

ただいまの
回答率

89.06%

[iOS/swift]タブ切替え(縦スクロールあり)画面でセル内の各コントロールのタップイベントを取得したい

解決済

回答 2

投稿 編集

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

entaro12345

score 33

前提・実現したいこと

SwiftでコードのみでiOSアプリを実装しています。
上部にタグを設置して各タグを選択時に下部のViewを切り替えて、各View内は行単位で情報を表示しています。
その行単位でセットしている中で画像をいくつかセットしているのですが、その画像をタップしたときのイベントを取得したいです。

↓View内の各行のイメージ
----------------
〇〇 △△ 画像① 画像② 画像③
----------------

画像①~③のタップ時にそれぞれの動作をさせたいです。
例)
画像①タップ時:B画面へ遷移
画像②タップ時:再読み込み
画像③タップ時:C画面へ遷移

※伝わりづらくてすみませんが、お力を貸してください。

お力添えをいただきタップイベントは取得できましたので、ソースコードを修正しました。
→タップしたものの判別処理で悩んでいます。

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

●CAPSPageMenuを使用してタブによる画面の切り換えは動作しています。
→縦スクロールもしたいため、scrollviewを使用してViewの実装を行うとタップイベントが取得できない
→scrollview用のクラスを作成してみたのですが、反応せず。

該当のソースコード

import UIKit

class ViewController: UIViewController {

    var activityIndicator: UIActivityIndicatorView!
    var pageMenu : CAPSPageMenu?
    var dispatch = DispatchGroup()

    var controllerArray : [UIViewController] = []
    var viewCtl         : SubViewController!

    var iWidthScreen:CGFloat  = 0.0
    var iHeightScreen:CGFloat = 0.0

    override func viewDidLoad() {
        super.viewDidLoad()

        // プログレスバー表示
        activityIndicator = UIActivityIndicatorView()
        activityIndicator.color = UIColor.gray
        activityIndicator.transform = CGAffineTransform(scaleX: 3, y: 3)
        activityIndicator.frame = CGRect(x: 0, y: self.view.frame.height * 0.7, width: self.view.frame.width, height: 100)
        activityIndicator.hidesWhenStopped = true
        self.view.addSubview(activityIndicator)
        activityIndicator.startAnimating()

        // 画面サイズを取得する
        iWidthScreen  = self.view.frame.size.width
        iHeightScreen = self.view.frame.size.height

        // タイトル
        let lblTitleFacility = UILabel()
        lblTitleFacility.frame = CGRect(x: 0, y: 45, width: iWidthScreen - 10, height: 5)
        lblTitleFacility.text  = "タイトル"
        lblTitleFacility.textColor = UIColor.white
        lblTitleFacility.font = UIFont.systemFont(ofSize: 16)
        lblTitleFacility.textAlignment = NSTextAlignment.center
        self.view.addSubview(lblTitleFacility)
    }

    override func viewDidAppear(_ animated: Bool) {
        // APIから情報を取得
        let sParam = 省略
        let sData  = sParam.data(using: String.Encoding.utf8)

        // info.plistファイルに設定しAPIのURLを表示
        let urlString = 省略

        if let url = URL(string: urlString!) {
            let req = NSMutableURLRequest(url: url)
            self.dispatch = DispatchGroup()
            self.dispatch.enter()
            req.httpMethod = "POST"
            req.httpBody   = sData
            let task = URLSession.shared.dataTask(with: req as URLRequest, completionHandler: { (data, resp, err) in
                do {
                    let json:NSArray = try! JSONSerialization.jsonObject(with: data!, options: JSONSerialization.ReadingOptions.mutableContainers) as! NSArray

                    for data in json {
                        // データ取得
                        let aData = data as! Dictionary<String, AnyObject>
                        // タブの追加
                        self.viewCtl = SubViewController()
                        // タブ名をセット
                        self.viewCtl.title = "タブ"
                        // 各種コントロールセット
                        省略
                    }
                    self.dispatch.leave()
                }
            })
            task.resume()
        }

        dispatch.notify(queue: .main) {
            // PageMenuの設定
            let parameters: [CAPSPageMenuOption] = [
                .bottomMenuHairlineColor(CustomClass.CustomUIColor().rgba()),
                .centerMenuItems(true),
                .menuItemFont(UIFont.systemFont(ofSize: 14)),
                .menuItemSeparatorWidth(4.3),
                .menuItemSeparatorPercentageHeight(0.1),
                .menuItemWidthBasedOnTitleTextWidth(true),
                .selectedMenuItemLabelColor(CustomClass.CustomUIColor().rgba()),
                .selectionIndicatorColor(CustomClass.CustomUIColor().rgba()),
                .unselectedMenuItemLabelColor(UIColor.white)
            ]
            // PageMenuのビューのサイズを設定
            self.pageMenu = CAPSPageMenu(viewControllers: self.controllerArray, frame: CGRect(x:0, y:70, width:self.view.frame.width, height:self.view.frame.height * 0.86), pageMenuOptions: parameters)
            // PageMenuのビューを親のビューに追加
            self.view.addSubview(self.pageMenu!.view)
            // PageMenuのビューをToolbarの後ろへ移動
            self.view.sendSubviewToBack(self.pageMenu!.view)
            self.pageMenu!.didMove(toParent: self)

            self.activityIndicator.stopAnimating()
        }
    }

}
import UIKit

class SubViewController: UIViewController, UIGestureRecognizerDelegate {

    override func viewDidLoad() {
        super.viewDidLoad()

        // 画面サイズを取得する
        let iWidthScreen:CGFloat  = self.view.frame.size.width
        let iHeightScreen:CGFloat = self.view.frame.size.height

        // タップのインスタンス生成
        let tapGesture:UITapGestureRecognizer = UITapGestureRecognizer(target: self, action: #selector(self.tapped(_:)))
        tapGesture.delegate = self
        self.view.addGestureRecognizer(tapGesture)

        let scrollView = CustomScrollView()
        scrollView.frame = CGRect(x: 0, y: 15, width: iWidthScreen, height: iHeightScreen * 0.8)
        scrollView.contentSize = CGSize(width: iWidthScreen, height: 750) // 80 * n + 30
        scrollView.isUserInteractionEnabled = true

        // 1セル分のコントロールを生成する
        let view = UIView()
        view.frame = CGRect(x: 5, y: Int(80 * iNum - 60), width: Int(iWidthScreen - 10), height: 65)
        view.layer.borderWidth = 1
        view.layer.borderColor = UIColor.gray.cgColor
        view.isUserInteractionEnabled = true

        // サイズを取得する
        let iWidthVScreen:CGFloat  = view.frame.size.width
        let iHeightVScreen:CGFloat = view.frame.size.height

        // 各コントロールを配置
        let sw = UISwitch()
        sw.frame = CGRect(x: 5, y: Int(iHeightVScreen * 0.3), width: Int(iWidthVScreen * 0.2), height: 5)
        sw.transform = CGAffineTransform(scaleX: 0.75, y: 0.75)
        view.addSubview(sw)

        // 名前
        let lblName       = UILabel()
        lblName.frame     = CGRect(x: iWidthVScreen * 0.15, y: iHeightVScreen * 0.3, width: iWidthVScreen * 0.3, height: iHeightVScreen * 0.4)
        lblName.text      = "名前"
        lblName.textColor = UIColor.white
        lblName.font      = UIFont.boldSystemFont(ofSize: 22)
        view.addSubview(lblName)

        // 年齢
        let lblAge       = UILabel()
        lblAge.frame     = CGRect(x: iWidthVScreen * 0.15, y: iHeightVScreen * 0.3, width: iWidthVScreen * 0.3, height: iHeightVScreen * 0.4)
        lblAge.text      = "20歳"
        lblAge.textColor = UIColor.white
        lblAge.font      = UIFont.boldSystemFont(ofSize: 22)
        view.addSubview(lblAge)

        // 画像1
        let imgone       = UIImage(named: image1)
        let imgViewone   = UIImageView(image: imgone)
        imgViewone.frame = CGRect(x: iWidthVScreen * 0.8, y: iHeightVScreen * 0.3, width: 30, height: 30)
        imgViewone.tag   = 100
        view.addSubview(imgViewone)

        // 画像2
        let imgtwo       = UIImage(named: image2)
        let imgViewtwo   = UIImageView(image: imgtwo)
        imgViewtwo.frame = CGRect(x: iWidthVScreen * 0.8, y: iHeightVScreen * 0.3, width: 30, height: 30)
        imgViewtwo.tag   = 200
        view.addSubview(imgViewtwo)

        // 画像3
        let imgthree       = UIImage(named: image3)
        let imgViewthree   = UIImageView(image: imgthree)
        imgViewthree.frame = CGRect(x: iWidthVScreen * 0.8, y: iHeightVScreen * 0.3, width: 30, height: 30)
        imgViewthree.tag   = 300
        view.addSubview(imgViewthree)

        scrollView.addSubview(view)
        self.view.addSubview(scrollView)
    }

    @objc func tapped(_ sender: UITapGestureRecognizer) {
        if sender.state == .ended {
            print("タップしました!")
        }
    }

}

補足情報(FW/ツールのバージョンなど)

Mac
Swift 3
iOS

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

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

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

    クリップを取り消します

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

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

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

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

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

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

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

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

    質問の評価を下げる

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

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

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

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

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

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

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

    詳細な説明はこちら

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

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

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

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

  • entaro12345

    2019/12/06 10:05

    UITapGestureRecognizerを使用することでタップ時イベントのトリガーは成功しました。

    タップされたものを判別するにはどのようにすればよいのでしょうか?
    恐れ入りますが、ご教示ください。

    キャンセル

  • MasatoUchida

    2019/12/06 16:16

    UITapGestureRecognizerで対応したメソッドの引数にUITapGestureRecognizerがあるかと思いますが、そこからviewを取得し後は今まで通りtagで判別すればいいのではないでしょうか。
    UITapGestureRecognizerの対応結果も質問に追記して頂けますと、回答しやすく助かります。

    キャンセル

  • entaro12345

    2019/12/06 19:05 編集

    失礼いたしました。
    現在のソースコードを追記します。

    キャンセル

回答 2

+1

質問者は一つで書いてるんだから、そんなに頑張っていくつも作らなくていいんじゃない?

import UIKit

class ViewController: UIViewController {

    @IBOutlet weak var aLabel: UILabel!
    @IBOutlet weak var bLabel: UILabel!

    override func viewDidLoad() {
        super.viewDidLoad()
        self.view.addGestureRecognizer(setTapGesture())
    }

    private func setTapGesture() -> UITapGestureRecognizer {
        let tap = UITapGestureRecognizer(target: self, action: #selector(tapped(_ :)))
        tap.cancelsTouchesInView = true
        return tap
    }

    @objc func tapped(_ sender: UITapGestureRecognizer) {
        let point = sender.location(in: self.view)

        if aLabel.frame.contains(point) {
            print("A")
        } else if bLabel.frame.contains(point) {
            print("B")
        } else {
            print("none")
        }
    }

}

投稿

編集

  • 回答の評価を上げる

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

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

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

  • 回答の評価を下げる

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

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

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

  • 2019/12/09 15:59

    「画像①~③のタップ時にそれぞれの動作をさせたいです。」
    とあるので、最低でも3つは必要なんではないでしょうか?

    と、思いましたが、画面上のtapした位置で分岐するのなら、
    確かに1つでいいみたいですね。
    tagを使わない方法ですね。
    勉強になります。

    キャンセル

  • 2019/12/10 08:37 編集

    試して問題なく動くことを確認しました。

    キャンセル

checkベストアンサー

-1

コード拝見させていただきました。

tapGestureの設定の仕方に間違いがあると思います。
self.viewにaddGestureしていますが、それだと、
一番背景のUIViewにのみ設定されている状態です。

それぞれのUILabelやUIImageViewにaddGestureしないと
LabelやImageViewを押したというイベントは取得できません。

また、どれが押されたか判別するには、
単純にtapGestureを何個も作り、それぞれの部品に別のgestureを接続する方法と、
各部品にtagをつけて、senderのtagで分岐する方法があります。

追伸

さらによく調べて、試してみました。
stackOverflowに答えがありました。
自分も知りませんでしたが、tapGestureは同じインスタンスを使い回すことができないみたいです。
なので、UIView1個に対して、Gesture1個必要みたいです。
なので、同じGestureを使い回すと、最後の1個のみしか正しく動かないという現象が起きるみたいです。

解決策としてはstackOverFlowにもありますが、
UITapGestureRecognizerを返す、private funcを作成してしまうことですね。
下記にサンプル載せます。

import UIKit

class ViewController: UIViewController, UIGestureRecognizerDelegate {

    @IBOutlet weak var labelA: UILabel!
    @IBOutlet weak var labelB: UILabel!
    @IBOutlet weak var labelC: UILabel!

    private func setTapGesture() -> UITapGestureRecognizer {
        let tap = UITapGestureRecognizer(target: self, action: #selector(tapped(_ :)))
        tap.cancelsTouchesInView = true
        return tap
    }

    override func viewDidLoad() {
        super.viewDidLoad()
        // Do any additional setup after loading the view.
        self.labelA.tag = 100
        self.labelB.tag = 200
        self.labelC.tag = 300
        self.labelA.isUserInteractionEnabled = true
        self.labelB.isUserInteractionEnabled = true
        self.labelC.isUserInteractionEnabled = true
        self.labelA.addGestureRecognizer(setTapGesture())
        self.labelB.addGestureRecognizer(setTapGesture())
        self.labelC.addGestureRecognizer(setTapGesture())
    }

    @objc func tapped(_ sender: UITapGestureRecognizer) {
        print("tapped tag:", sender.view?.tag)
        switch sender.view?.tag {
        case 100:
            // ここで何かをする
            break
        case 200:
            // ここで何かをする
            break
        case 300:
            // ここで何かをする
            break
        default:
            break
        }
    }

}


答えを修正します。

投稿

編集

  • 回答の評価を上げる

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

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

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

  • 回答の評価を下げる

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

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

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

  • この投稿は削除されました

  • 2019/12/09 12:39

    さらに調べて、実装してみました。
    答えを修正します。

    キャンセル

  • 2019/12/09 13:03

    本当にありがとうございます。
    教えていただいた実装をして、動作することが確認できました。
    コードまで載せていただきほんとうにありがとうございました。

    キャンセル

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

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

関連した質問

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

  • トップ
  • iOSに関する質問
  • [iOS/swift]タブ切替え(縦スクロールあり)画面でセル内の各コントロールのタップイベントを取得したい