🎄teratailクリスマスプレゼントキャンペーン2024🎄』開催中!

\teratail特別グッズやAmazonギフトカード最大2,000円分が当たる!/

詳細はこちら
iOS

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

イベントハンドラ

マウスのクリックなどの特定の事象(イベント)が発生した時に実行される処理のことをイベントハンドラと呼びます。

スクロール

スクロールとは、ディスプレイスクリーン上において連続的にコンテンツが滑っていくことを指します。

Swift

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

Q&A

解決済

2回答

1151閲覧

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

entaro12345

総合スコア75

iOS

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

イベントハンドラ

マウスのクリックなどの特定の事象(イベント)が発生した時に実行される処理のことをイベントハンドラと呼びます。

スクロール

スクロールとは、ディスプレイスクリーン上において連続的にコンテンツが滑っていくことを指します。

Swift

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

0グッド

0クリップ

投稿2019/12/04 09:37

編集2019/12/06 10:35

前提・実現したいこと

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

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

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

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

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

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

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

該当のソースコード

ViewController

1import UIKit 2 3class ViewController: UIViewController { 4 5 var activityIndicator: UIActivityIndicatorView! 6 var pageMenu : CAPSPageMenu? 7 var dispatch = DispatchGroup() 8 9 var controllerArray : [UIViewController] = [] 10 var viewCtl : SubViewController! 11 12 var iWidthScreen:CGFloat = 0.0 13 var iHeightScreen:CGFloat = 0.0 14 15 override func viewDidLoad() { 16 super.viewDidLoad() 17 18 // プログレスバー表示 19 activityIndicator = UIActivityIndicatorView() 20 activityIndicator.color = UIColor.gray 21 activityIndicator.transform = CGAffineTransform(scaleX: 3, y: 3) 22 activityIndicator.frame = CGRect(x: 0, y: self.view.frame.height * 0.7, width: self.view.frame.width, height: 100) 23 activityIndicator.hidesWhenStopped = true 24 self.view.addSubview(activityIndicator) 25 activityIndicator.startAnimating() 26 27 // 画面サイズを取得する 28 iWidthScreen = self.view.frame.size.width 29 iHeightScreen = self.view.frame.size.height 30 31 // タイトル 32 let lblTitleFacility = UILabel() 33 lblTitleFacility.frame = CGRect(x: 0, y: 45, width: iWidthScreen - 10, height: 5) 34 lblTitleFacility.text = "タイトル" 35 lblTitleFacility.textColor = UIColor.white 36 lblTitleFacility.font = UIFont.systemFont(ofSize: 16) 37 lblTitleFacility.textAlignment = NSTextAlignment.center 38 self.view.addSubview(lblTitleFacility) 39 } 40 41 override func viewDidAppear(_ animated: Bool) { 42 // APIから情報を取得 43 let sParam = 省略 44 let sData = sParam.data(using: String.Encoding.utf8) 45 46 // info.plistファイルに設定しAPIのURLを表示 47 let urlString = 省略 48 49 if let url = URL(string: urlString!) { 50 let req = NSMutableURLRequest(url: url) 51 self.dispatch = DispatchGroup() 52 self.dispatch.enter() 53 req.httpMethod = "POST" 54 req.httpBody = sData 55 let task = URLSession.shared.dataTask(with: req as URLRequest, completionHandler: { (data, resp, err) in 56 do { 57 let json:NSArray = try! JSONSerialization.jsonObject(with: data!, options: JSONSerialization.ReadingOptions.mutableContainers) as! NSArray 58 59 for data in json { 60 // データ取得 61 let aData = data as! Dictionary<String, AnyObject> 62 // タブの追加 63 self.viewCtl = SubViewController() 64 // タブ名をセット 65 self.viewCtl.title = "タブ" 66 // 各種コントロールセット 67 省略 68 } 69 self.dispatch.leave() 70 } 71 }) 72 task.resume() 73 } 74 75 dispatch.notify(queue: .main) { 76 // PageMenuの設定 77 let parameters: [CAPSPageMenuOption] = [ 78 .bottomMenuHairlineColor(CustomClass.CustomUIColor().rgba()), 79 .centerMenuItems(true), 80 .menuItemFont(UIFont.systemFont(ofSize: 14)), 81 .menuItemSeparatorWidth(4.3), 82 .menuItemSeparatorPercentageHeight(0.1), 83 .menuItemWidthBasedOnTitleTextWidth(true), 84 .selectedMenuItemLabelColor(CustomClass.CustomUIColor().rgba()), 85 .selectionIndicatorColor(CustomClass.CustomUIColor().rgba()), 86 .unselectedMenuItemLabelColor(UIColor.white) 87 ] 88 // PageMenuのビューのサイズを設定 89 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) 90 // PageMenuのビューを親のビューに追加 91 self.view.addSubview(self.pageMenu!.view) 92 // PageMenuのビューをToolbarの後ろへ移動 93 self.view.sendSubviewToBack(self.pageMenu!.view) 94 self.pageMenu!.didMove(toParent: self) 95 96 self.activityIndicator.stopAnimating() 97 } 98 } 99 100}

SubViewController

1import UIKit 2 3class SubViewController: UIViewController, UIGestureRecognizerDelegate { 4 5 override func viewDidLoad() { 6 super.viewDidLoad() 7 8 // 画面サイズを取得する 9 let iWidthScreen:CGFloat = self.view.frame.size.width 10 let iHeightScreen:CGFloat = self.view.frame.size.height 11 12 // タップのインスタンス生成 13 let tapGesture:UITapGestureRecognizer = UITapGestureRecognizer(target: self, action: #selector(self.tapped(_:))) 14 tapGesture.delegate = self 15 self.view.addGestureRecognizer(tapGesture) 16 17 let scrollView = CustomScrollView() 18 scrollView.frame = CGRect(x: 0, y: 15, width: iWidthScreen, height: iHeightScreen * 0.8) 19 scrollView.contentSize = CGSize(width: iWidthScreen, height: 750) // 80 * n + 30 20 scrollView.isUserInteractionEnabled = true 21 22 // 1セル分のコントロールを生成する 23 let view = UIView() 24 view.frame = CGRect(x: 5, y: Int(80 * iNum - 60), width: Int(iWidthScreen - 10), height: 65) 25 view.layer.borderWidth = 1 26 view.layer.borderColor = UIColor.gray.cgColor 27 view.isUserInteractionEnabled = true 28 29 // サイズを取得する 30 let iWidthVScreen:CGFloat = view.frame.size.width 31 let iHeightVScreen:CGFloat = view.frame.size.height 32 33 // 各コントロールを配置 34 let sw = UISwitch() 35 sw.frame = CGRect(x: 5, y: Int(iHeightVScreen * 0.3), width: Int(iWidthVScreen * 0.2), height: 5) 36 sw.transform = CGAffineTransform(scaleX: 0.75, y: 0.75) 37 view.addSubview(sw) 38 39 // 名前 40 let lblName = UILabel() 41 lblName.frame = CGRect(x: iWidthVScreen * 0.15, y: iHeightVScreen * 0.3, width: iWidthVScreen * 0.3, height: iHeightVScreen * 0.4) 42 lblName.text = "名前" 43 lblName.textColor = UIColor.white 44 lblName.font = UIFont.boldSystemFont(ofSize: 22) 45 view.addSubview(lblName) 46 47 // 年齢 48 let lblAge = UILabel() 49 lblAge.frame = CGRect(x: iWidthVScreen * 0.15, y: iHeightVScreen * 0.3, width: iWidthVScreen * 0.3, height: iHeightVScreen * 0.4) 50 lblAge.text = "20歳" 51 lblAge.textColor = UIColor.white 52 lblAge.font = UIFont.boldSystemFont(ofSize: 22) 53 view.addSubview(lblAge) 54 55 // 画像1 56 let imgone = UIImage(named: image1) 57 let imgViewone = UIImageView(image: imgone) 58 imgViewone.frame = CGRect(x: iWidthVScreen * 0.8, y: iHeightVScreen * 0.3, width: 30, height: 30) 59 imgViewone.tag = 100 60 view.addSubview(imgViewone) 61 62 // 画像2 63 let imgtwo = UIImage(named: image2) 64 let imgViewtwo = UIImageView(image: imgtwo) 65 imgViewtwo.frame = CGRect(x: iWidthVScreen * 0.8, y: iHeightVScreen * 0.3, width: 30, height: 30) 66 imgViewtwo.tag = 200 67 view.addSubview(imgViewtwo) 68 69 // 画像3 70 let imgthree = UIImage(named: image3) 71 let imgViewthree = UIImageView(image: imgthree) 72 imgViewthree.frame = CGRect(x: iWidthVScreen * 0.8, y: iHeightVScreen * 0.3, width: 30, height: 30) 73 imgViewthree.tag = 300 74 view.addSubview(imgViewthree) 75 76 scrollView.addSubview(view) 77 self.view.addSubview(scrollView) 78 } 79 80 @objc func tapped(_ sender: UITapGestureRecognizer) { 81 if sender.state == .ended { 82 print("タップしました!") 83 } 84 } 85 86}

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

Mac
Swift 3
iOS

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

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

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

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

MasatoUchida

2019/12/05 01:58

タップイベント取得の仕方が個人的にしっくりこないので、UITapGestureRecognizerを使用してみていただけますでしょうか。またprintを挟むなどしてログを出しタップ自体はきているのか等の確認もお願いします。
fuzzball

2019/12/05 02:51

この質問にCAPSPageMenuとかタブ切り替えは関係しているのでしょうか? CustomScrollView単体だとタップイベントを取得できているということですか?
fuzzball

2019/12/05 02:59

あと、CustomScrollViewの正しいコードを書いてください。(コピペして下さい)
fuzzball

2019/12/05 04:13 編集

UIImageViewのタップを取得したいのだと思いますが、おそらくこのまま進めてもアチコチで躓くことになると思うので、MasatoUchidaさんの書かれているように、UITapGestureRecognizerを使うことをお勧めします。 もしかしたらUIImageViewの代わりにUIButtonを使えるかもしれません。
entaro12345

2019/12/05 23:30

MasatoUchidaさま、fuzzballさま 連絡遅くなりすみません。 ご回答ありがとうございます。 UITapGestureRecognizerを使用して実装してみます。
entaro12345

2019/12/06 01:05

UITapGestureRecognizerを使用することでタップ時イベントのトリガーは成功しました。 タップされたものを判別するにはどのようにすればよいのでしょうか? 恐れ入りますが、ご教示ください。
MasatoUchida

2019/12/06 07:16

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

2019/12/06 10:32 編集

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

回答2

0

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

swift

1import UIKit 2 3class ViewController: UIViewController { 4 5 @IBOutlet weak var aLabel: UILabel! 6 @IBOutlet weak var bLabel: UILabel! 7 8 override func viewDidLoad() { 9 super.viewDidLoad() 10 self.view.addGestureRecognizer(setTapGesture()) 11 } 12 13 private func setTapGesture() -> UITapGestureRecognizer { 14 let tap = UITapGestureRecognizer(target: self, action: #selector(tapped(_ :))) 15 tap.cancelsTouchesInView = true 16 return tap 17 } 18 19 @objc func tapped(_ sender: UITapGestureRecognizer) { 20 let point = sender.location(in: self.view) 21 22 if aLabel.frame.contains(point) { 23 print("A") 24 } else if bLabel.frame.contains(point) { 25 print("B") 26 } else { 27 print("none") 28 } 29 } 30 31} 32

投稿2019/12/09 06:26

編集2019/12/09 06:30
退会済みユーザー

退会済みユーザー

総合スコア0

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

hameji

2019/12/09 06:59

「画像①~③のタップ時にそれぞれの動作をさせたいです。」 とあるので、最低でも3つは必要なんではないでしょうか? と、思いましたが、画面上のtapした位置で分岐するのなら、 確かに1つでいいみたいですね。 tagを使わない方法ですね。 勉強になります。
hameji

2019/12/10 01:40 編集

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

0

ベストアンサー

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

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を作成してしまうことですね。
下記にサンプル載せます。

Swift

1import UIKit 2 3class ViewController: UIViewController, UIGestureRecognizerDelegate { 4 5 @IBOutlet weak var labelA: UILabel! 6 @IBOutlet weak var labelB: UILabel! 7 @IBOutlet weak var labelC: UILabel! 8 9 private func setTapGesture() -> UITapGestureRecognizer { 10 let tap = UITapGestureRecognizer(target: self, action: #selector(tapped(_ :))) 11 tap.cancelsTouchesInView = true 12 return tap 13 } 14 15 override func viewDidLoad() { 16 super.viewDidLoad() 17 // Do any additional setup after loading the view. 18 self.labelA.tag = 100 19 self.labelB.tag = 200 20 self.labelC.tag = 300 21 self.labelA.isUserInteractionEnabled = true 22 self.labelB.isUserInteractionEnabled = true 23 self.labelC.isUserInteractionEnabled = true 24 self.labelA.addGestureRecognizer(setTapGesture()) 25 self.labelB.addGestureRecognizer(setTapGesture()) 26 self.labelC.addGestureRecognizer(setTapGesture()) 27 } 28 29 @objc func tapped(_ sender: UITapGestureRecognizer) { 30 print("tapped tag:", sender.view?.tag) 31 switch sender.view?.tag { 32 case 100: 33 // ここで何かをする 34 break 35 case 200: 36 // ここで何かをする 37 break 38 case 300: 39 // ここで何かをする 40 break 41 default: 42 break 43 } 44 } 45 46} 47

答えを修正します。

投稿2019/12/07 14:59

編集2019/12/09 03:52
hameji

総合スコア1380

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

entaro12345

2019/12/08 23:33

回答ありがとうございます。 各コントロール一つずつにaddGestureしないと判別が厳しいということですね・・。 UIViewにaddGestureして、その配下のコントロールを取得できて判別できるものだと思っておりました。 ありがとうございます、実装してみます。
hameji

2019/12/08 23:35

あのー、****する方法と、 「各部品にtagをつけて、senderのtagで分岐する方法があります。」 と書いたように、どっちでもできますが、、、
hameji

2019/12/09 03:39

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

2019/12/09 04:03

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

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.36%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問