Trzeba już pisać app-kę na iOS-a. Dziś przedstawię pierwsze kroki poczynione w interfejsie użytkownika i przy odtwarzaniu plików audio.
Obecna wersja zawiera następujący ekran:
Naciśnięcie ikony Search na pasku nawigacyjnym spowoduje otwarcie systemowego widoku, z poziomu którego możemy wybrać utwory do odtwarzania:
Jeśli jakiś utwór jest odtwarzany lub jesteśmy w trakcie pauzy na dole pierwszego czarnego ekranu znajdziemy toolbar pozwalający włączyć odtwarzanie/pauzę. Większość jego obszaru zajmuje tytuł utworu, którego dotyczą te operacje. Muzyka odtwarzana jest także w tle, kiedy opuścimy aplikację.
Jak to osiągnęliśmy?
Jeśli chodzi o UI przełożyło się to na kilka chwytów.
Przy pasku nawigacyjnym może okazać się pomocny tutorial https://developer.apple.com/library/ios/referencelibrary/GettingStarted/DevelopiOSAppsSwift/Lesson8.html. Dodatkowo ustawiłem jego styl na Black. Zdarzenie kliknięcia robimy tradycyjnie jak na Xcode, czyli trzymając CTRL przeciągamy na plik z kodem kontrolera i wybieramy w oknie, że chcemy akcję.
Przy pasku narzędziowym przydatny okazał się przykład z rozdziału 12-tego książki More iPhone Development with Swift, Exploring the iOS SDK, który przede wszystkim jest bardzo dobrym przewodnikiem po multimediach w iOS (po tych wysokopoziomowych). Wzorując się na aplikacji Music zapragnąłem jednak w toolbarze umieścić zwykłą labelkę jako tytuł granej piosenki. Aby to zrobić posłużyłem się sztuczką ze strony https://www.depicus.com/blog/adding-a-uilabel-to-a-uitoolbar-the-easy-way/. Dzięki niej robimy wszystko za pomocą designera, bez dopisywania linijki kodu. Pamiętam, że tutaj były jeszcze różne przypadłości z layoutem, z którymi uporałem się kontrolując warunki w designerze Xcode (widzimy je w strukturze po lewej w designerze Storyboard, na dole ekranu część ikon także jest przydatna - Align i Pin). Akcję do przycisku w toolbarze podpinamy tak jak do każdego innego przycisku. Dodatkowo zrobiłem outlet (referencję) na labelkę z poziomu kodu, by móc ją aktualizować.
Oba paski - nawigacyjny i narzędziowy - układają się prawidłowo zarówno w orientacji pionowej, jak i poziomej ekranu (w nawigacyjnym nic nie robiłem, w toolbarze upewniłem się tylko co do warunków na lyout, na początku “zrobiła się” sztywna odległość “od góry”, która bruździła).
Teraz omówimy logikę, która zamyka się w kontolerze ViewController:
import UIKit
import MediaPlayer
class ViewController: UIViewController, MPMediaPickerControllerDelegate {
@IBOutlet weak var toolbar: UIToolbar!
@IBOutlet weak var song: UILabel!
@IBOutlet var playButton: UIBarButtonItem!
var pauseButton: UIBarButtonItem!
var player: MPMusicPlayerController!
var collection: MPMediaItemCollection!
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
self.pauseButton = UIBarButtonItem(barButtonSystemItem: .Pause, target: self,
action: #selector(ViewController.playPausePressed(_:)))
self.pauseButton.style = .Plain
self.player = MPMusicPlayerController.systemMusicPlayer()
self.player.repeatMode = .All
let notificationCenter = NSNotificationCenter.defaultCenter()
notificationCenter.addObserver(self, selector: #selector(ViewController.nowPlayingItemChanged(_:)),
name: MPMusicPlayerControllerNowPlayingItemDidChangeNotification, object: self.player)
notificationCenter.addObserver(self, selector: #selector(ViewController.playbackStateChanged(_:)),
name: MPMusicPlayerControllerPlaybackStateDidChangeNotification, object: self.player)
self.player.beginGeneratingPlaybackNotifications()
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
NSNotificationCenter.defaultCenter().removeObserver(self, name: MPMusicPlayerControllerNowPlayingItemDidChangeNotification, object: self.player)
NSNotificationCenter.defaultCenter().removeObserver(self, name: MPMusicPlayerControllerPlaybackStateDidChangeNotification, object: self.player)
}
@IBAction func search(sender: AnyObject) {
let picker = MPMediaPickerController(mediaTypes: MPMediaType.Music)
picker.delegate = self
picker.allowsPickingMultipleItems = true
picker.prompt = NSLocalizedString("Select items to play", comment: "Select items to play")
self.presentViewController(picker, animated: true, completion: nil)
}
func mediaPickerDidCancel(mediaPicker: MPMediaPickerController) {
self.dismissViewControllerAnimated(true, completion: nil)
}
func mediaPicker(mediaPicker: MPMediaPickerController, didPickMediaItems mediaItemCollection: MPMediaItemCollection) {
self.dismissViewControllerAnimated(true, completion: nil)
self.collection = mediaItemCollection
self.player.setQueueWithItemCollection(self.collection)
var playbackState = self.player.playbackState as MPMusicPlaybackState
if playbackState == .Playing {
self.player.pause()
}
let item = self.collection.items[0] as MPMediaItem
self.player.nowPlayingItem = item
playbackState = self.player.playbackState as MPMusicPlaybackState
self.player.play()
}
@IBAction func playPausePressed(sender: AnyObject) {
let playbackState = self.player.playbackState as MPMusicPlaybackState
if playbackState == .Stopped || playbackState == .Paused {
self.player.play()
} else if playbackState == .Playing {
self.player.pause()
}
}
func nowPlayingItemChanged(notification: NSNotification) {
if let currentItem = self.player.nowPlayingItem as MPMediaItem? {
self.song.text = currentItem.valueForProperty(MPMediaItemPropertyTitle) as? String
} else {
self.song.text = nil
}
}
func playbackStateChanged(notification: NSNotification) {
let playbackState = self.player.playbackState as MPMusicPlaybackState
self.toolbar.hidden = playbackState != .Playing && playbackState != .Paused
var items = self.toolbar.items!
if playbackState == .Stopped || playbackState == .Paused {
items[0] = self.playButton
} else if playbackState == .Playing {
items[0] = self.pauseButton
}
self.toolbar.setItems(items, animated: false)
}
}
Z tematem audio związane są różne możliwości, na razie zrobiliśmy pierwsze podejście z odtwarzaniem w oparciu o MediaPlayer Framework bez ukierunkowania na analizę dźwięku, raczej nie jest to ostatnie słowo.
Wyszukiwanie i pobieranie plików z Music Library na telefonie możemy zrealizować albo przy pomocy gotowego kontrolera MPMediaPickerController (zwróćmy uwagę na metodę search, a także mediaPicker - sukces i mediaPickerDidCancel - anulowanie) albo poprzez napisanie zapytań i własne UI. Dzisiaj zastosowaliśmy pierwsze podejscie, ale następnym razem pomyślimy nad drugą opcją.
Odtwarzanie realizujemy przy pomocy MPMusicPlayerController.systemMusicPlayer (iPodMusicPlayer jest deprecated), który działa również w tle. Nie trzeba nigdzie już samemu definiować pozwoleń z tym związanych. Za pomocą odpowiednich notyfikacji nasłuchujemy zmian stanu odtwarzacza, jak również aktualnie wybranego w nim utworu. Wybrane piosenki są odtwarzane w pętli nieskończoną ilość razy (repeatMode w odtwarzaczu). Edytor Xcode usłużnie podpowiada, co zrobiliśmy nie tak lub co jest deprecated. Dawniej np. referencje do callback-ów przekazywało się w postaci stringa jak w Objective-C, teraz należy posługiwać się konstrukcją #selector.
Brak komentarzy:
Prześlij komentarz