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

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

新規登録して質問してみよう
ただいま回答率
85.50%
TableView

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

iOS

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

Xcode

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

Swift

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

Q&A

解決済

1回答

4443閲覧

【iOS】Collection Viewの特定セルのみの更新について

Ethan

総合スコア8

TableView

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

iOS

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

Xcode

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

Swift

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

0グッド

0クリップ

投稿2017/04/19 13:35

編集2017/04/20 09:06

###前提・実現したいこと
ご覧いただき、ありがとうございます。
現在、Collection ViewのCell内に音声を再生するためのボタンを置き、
ストリーミングで再生する機能を作っています。

下記のコードでは、音声が再生されているかを調べ、
再生ボタンと停止ボタンを分岐させています。

ですが、このやり方ですと、コレクションビューをスクロールすると、全てのセルに反映されてしまい、再生している時は全てのセルで停止ボタンが表示されてしまいます。

音声再生中の特定セルのみの再生状態を読み取り、再生中のセルのボタンの状態を変化させるには、どうすればよいのでしょうか?
また、他にベストな方法があるのでしょうか?

宜しくお願いします。

cell.playButton.setImage(UIImage(named: "play"), for: UIControlState.normal) cell.playButton.setImage(UIImage(named: "stop"), for: UIControlState.selected) cell.playButton.isSelected = false if !(mediaPlayer.rate == 0.0){ cell.playButton.isSelected = true }else{ cell.playButton.isSelected = false } cell.playButton.addTarget(self,action:#selector(playButtonDidTouch(sender:)), for: .touchUpInside)

###該当のソースコード

class AudioViewController: UIViewController { var mediaPlayer = AVPlayer() override func viewDidLoad() { super.viewDidLoad() } //コレクションビュー関連 extension AudioViewController : UICollectionViewDataSource { func numberOfSections(in collectionView: UICollectionView) -> Int { return 1 } func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int { return 10 } func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell { cell.playButton.tag = indexPath.row cell.playButton.setImage(UIImage(named: "play"), for: UIControlState.normal) cell.playButton.setImage(UIImage(named: "stop"), for: UIControlState.selected) cell.playButton.isSelected = false if !(mediaPlayer.rate == 0.0){ cell.playButton.isSelected = true }else{ cell.playButton.isSelected = false } cell.playButton.addTarget(self,action:#selector(playButtonDidTouch(sender:)), for: .touchUpInside) return cell } func playButtonDidTouch(sender:UIButton) { if (sender.isSelected){ mediaPlayer.pause() sender.isSelected = false } else{ let url = "" do { try AVAudioSession.sharedInstance().setCategory(AVAudioSessionCategoryPlayback)} catch {print("エラー")} let playerItem = AVPlayerItem( url:NSURL( string:url! )! as URL ) mediaPlayer = AVPlayer(playerItem:playerItem) mediaPlayer.rate = 1.0 mediaPlayer.play() sender.isSelected = true } } }

###試したこと

func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell { let cell = collectionView.dequeueReusableCell(withReuseIdentifier: Storyboard.CellIdentifier, for: indexPath) as! AudioCollectionViewCell cell.playButton.tag = indexPath.row if let optionalIndexPath = currentSelectedIndexPath{ if (indexPath == optionalIndexPath){ cell.playButton.setImage(UIImage(named: "stop"), for: UIControlState.selected) } else{ cell.playButton.setImage(UIImage(named: "play"), for: UIControlState.normal) } } cell.playButton.addTarget(self,action:#selector(playButtonDidTouch(sender:)), for: .touchUpInside) return cell } func playButtonDidTouch(sender:UIButton) { let cell = sender.superview?.superview as! UICollectionViewCell let indexPath = collectionView.indexPath(for: cell)! currentSelectedIndexPath = indexPath if (sender.isSelected){ mediaPlayer.pause() sender.isSelected = false sender.setImage(UIImage(named: "play"), for: UIControlState.normal) } else{ let row = sender.tag let url = "" do { try AVAudioSession.sharedInstance().setCategory(AVAudioSessionCategoryPlayback)} catch {print("エラー")} let playerItem = AVPlayerItem( url:NSURL( string:url! )! as URL ) mediaPlayer = AVPlayer(playerItem:playerItem) mediaPlayer.rate = 1.0 mediaPlayer.play() sender.isSelected = true sender.setImage(UIImage(named: "stop"), for: UIControlState.normal) } }

###補足情報(言語/FW/ツール等のバージョンなど)
Swift 3での実装

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

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

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

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

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

guest

回答1

0

ベストアンサー

再利用対策を実施したとのことですが、どのような再利用対策を実施したのでしょうか?
それが提示されていないので、どこまで理解されているのかわかりませんが、そのあたりの再利用対策が理解されていないような気がします。

通常の再利用対策は、collectionViewのセルに表示するデータを別途配列のプロパティで持っておき、cellForItemAtのメソッドでその配列内のデータをもとにセルの内容を再セットします。そうすれば、再利用前にセットされていたセルの表示は、正しい状態に再セットされます。

今回なら、セル毎のデータとして、ボタンの状態とか音声のURL(またはそれをもとに生成した音声データ)があるはずです。

ただ、今回の場合は、音声再生とのことですので、おそらくたくさんあるセルの中で最後にタップされたセルだけ再生状態にする(以前に再生していたセルの音声は停止し、ボタンも非選択状態にもどす)ようなことを期待しているような気がします。

もしそうであれば、配列データを持たなくても、「現在再生中のセルの番号」をプロパティで持っておき、cellForItemAtでセルの内容を再セットする際に、
・再生中のセル番号と一致していればセルを再生中の表示に設定する。
・一致していなければセルを非再生の表示に設定する。
といったようなことをすればよさそうに思います。

また、この場合、playButtonDidTouchの処理でどのセル番号のボタンがタップされたかの情報を取得して、「現在再生中のセルの番号」を更新する必要がありますが、
その処理は

swift

1let cell = sender.superview?.superview as! UICollectionViewCell 2let indexPath = collectionView.indexPath(for: cell)!

のようにすれば、ボタンがタップされたセルの番号を簡単に取得できます。

投稿2017/04/20 01:43

TakeOne

総合スコア6299

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

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

Ethan

2017/04/20 05:38

TakeOneさま 丁寧なご回答、まことにありがとうございます。 上記を試したところ、全てのセルには反映されなくなったのですが、 1つ目のセルの音声を再生すると、5個目と9個目のボタンも1つ目のボタンと連動して、変化してしまいます。連動させないようにするにはどうすれば良いのでしょうか...? また、音声を再生させながら前の画面に戻って、(タップされた変数をグローバル変数として持っています)、再度コレクションビュー内に戻ると、ボタンが全て停止ボタンでは無く、再生ボタンとして表示されてしまいます。 再利用対策で行ったのは、UICollectionCell内で、PrepareForReuseメソッド内において、 ボタンにnilを加え、初期化させました。 質問を続けてしまい、大変恐縮ですが、何卒宜しくお願いいたします。
TakeOne

2017/04/20 06:45 編集

> 1つ目のセルの音声を再生すると、5個目と9個目のボタンも1つ目のボタンと連動して、変化してしまいます。連動させないようにするにはどうすれば良いのでしょうか...? どのように修正されたのかコードを見せてもらわないとわかりません。 修正したコードを追記するときは、質問欄に追記してしてください。
Ethan

2017/04/20 08:59

TakeOneさま 大変、失礼いたしました。 『試したこと』の欄に追加したコードを追記しました。 ご確認宜しくお願い致します。
TakeOne

2017/04/20 16:05

currentSelectedIndexPathがどのように定義されているのか 肝心のところがありませんが、おそらく var currentSelectedIndexPath:IndexPath! という定義になっているのだろうと推測して見てみました。 ざっと見た限り、以下の問題があると思います。 1.cellForItemAtでoptionalIndexPathを見て setImageでstopかplayの画像を設定する処理がありますが、 ここで選択状態(cell.playButton.isSelected)の再設定が必要だと思います。 2.cellForItemAtで`if let optionalIndexPath = currentSelectedIndexPath` のオプショナルバインディング処理がありますが、これのelseルートは まだ1回もボタンを押してない状態の処理だと思うので、 cell.playButton.isSelectedとsender.setImageが必要だと思います。 3. playButtonDidTouchの最後に collectionView.reloadData()が必要だと思います。
Ethan

2017/04/21 01:41

TakeOneさま cellForItemAtで、選択状態(cell.playButton.isSelected)の再設定をしたところ、 期待通りの動きが得られました。情報不足で大変ご迷惑をおかけしました。 ありがとうございました!
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.50%

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

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

質問する

関連した質問