はじめに
オーディオプレーヤーの再生↔一時停止のようにツールバーをつくるとき、みなさんはどのように書いていますか。
- Storyboardをつかわない
- Swift4
- NavigationControllerをつかう
こんな条件のときのサンプルが見つけられなかったので、いろいろためしながら実装した方法を紹介したいとおもいます。
実行結果は、こんな感じになります。
この記事の最後に、Playgroundにコピペすると動作するコードを載せていますのでそちらも参考になれば
前準備
ビューの作成時に、self.toolbarItems
をセットしておく必要があります。
NavigationController
にツールバーを表示させる方法は、NavigationControllerのToolbarを特定のViewControllerでのみ有効にする - Qiitaを参考にしてみてください。
ボタンをトグルするコード
ボタンのオブジェクトはひとつにしてbarButtonSystemItem
を.play
と.pause
でトグルすればいいのでは?とおもったのですが、再生ボタンと一時停止ボタンの2つのオブジェクトを用意して差し替えるのがベターな方法みたいです。
private var audioPlaying = false
// MARK: ツールバーのアイテム
private var uiPlayButtonItem : UIBarButtonItem {
let button = UIBarButtonItem(
barButtonSystemItem: .play,
target: self,
action: #selector(onButton(_:)))
button.tag = 1
return button
}
private var uiPauseButtonItem : UIBarButtonItem {
let button = UIBarButtonItem(
barButtonSystemItem: .pause,
target: self,
action: #selector(onButton(_:)))
button.tag = 1 // 置換するのでtagはおなじ
return button
}
private lazy var uiButtonItems: [UIBarButtonItem] = {
let flexibleItem = UIBarButtonItem(barButtonSystemItem: UIBarButtonItem.SystemItem.flexibleSpace, target: nil, action: nil)
flexibleItem.tag = 0
return [
flexibleItem,
uiPauseButtonItem, // 最初は再生
flexibleItem,
]
}()
@objc func onButton(_ sender: UIBarButtonItem) {
// 再生ボタンを差し替えるので、index位置を取得する
guard let buttonIndex = self.uiButtonItems.firstIndex(
where: {$0.tag == 1}
) else {
print( "再生ボタンのインデックスが取得できてません")
return
}
if self.audioPlaying {
self.audioPlaying = false
self.toolbarItems?[buttonIndex] = self.uiPlayButtonItem
return
}
self.audioPlaying = true
self.toolbarItems?[buttonIndex] = self.uiPauseButtonItem
}
Playgroundで試せるコード
以下を実行すると、冒頭のスクショのような動作になります。
import UIKit
import XCPlayground
import PlaygroundSupport
class ViewController: UIViewController {
private var audioPlaying = false
let label = UILabel()
override func viewDidLoad() {
super.viewDidLoad()
view.backgroundColor = .white
label.textAlignment = .center
view.addSubview(label)
}
override func viewDidLayoutSubviews() {
super.viewDidLayoutSubviews()
label.frame = view.bounds
}
// ツールバーを表示する
override func viewWillAppear(_ animated: Bool) {
self.toolbarItems = self.uiButtonItems
self.updateButton()
self.updateLabel()
self.navigationController?.setToolbarHidden(false, animated: false)
}
override func viewWillDisappear(_ animated: Bool) {
self.navigationController?.setToolbarHidden(true, animated: false)
super.viewWillDisappear(animated)
}
// MARK: ツールバーのアイテム
private var uiPlayButtonItem : UIBarButtonItem {
let button = UIBarButtonItem(
barButtonSystemItem: .play,
target: self,
action: #selector(onButton(_:)))
button.tag = 1
return button
}
private var uiPauseButtonItem : UIBarButtonItem {
let button = UIBarButtonItem(
barButtonSystemItem: .pause,
target: self,
action: #selector(onButton(_:)))
button.tag = 1 // 置換するのでtagはおなじ
return button
}
private lazy var uiButtonItems: [UIBarButtonItem] = {
let flexibleItem = UIBarButtonItem(barButtonSystemItem: UIBarButtonItem.SystemItem.flexibleSpace, target: nil, action: nil)
flexibleItem.tag = 0
return [
flexibleItem,
uiPauseButtonItem, // 最初は再生
flexibleItem,
]
}()
func updateLabel() {
label.text = self.audioPlaying ? "playing..." : "pause"
}
func togglePlayState() {
self.audioPlaying = !self.audioPlaying
}
func updateButton() {
// 再生ボタンを差し替えるので、index位置を取得する
guard let buttonIndex = self.uiButtonItems.firstIndex(
where: {$0.tag == 1}
) else {
print( "再生ボタンのインデックスが取得できてません")
return
}
if self.audioPlaying {
self.toolbarItems?[buttonIndex] = self.uiPauseButtonItem
return
}
self.toolbarItems?[buttonIndex] = self.uiPlayButtonItem
}
@objc func onButton(_ sender: UIBarButtonItem) {
self.togglePlayState()
self.updateButton()
self.updateLabel()
}
}
var ctrl = ViewController()
let navigationController = UINavigationController(rootViewController: ctrl)
navigationController.view.frame = CGRect(x: 0, y: 0, width: 320, height: 480)
PlaygroundPage.current.needsIndefiniteExecution = true
PlaygroundPage.current.liveView = navigationController.view