I have some ViewCotroller where i tapped a button - some audio file is playing. I want to stop playing audio when change/close this ViewController. How I can do this?
I try add some method to viewWillDisappear and it crashed if I don't tap any button. But if I tapped some button - it will works fine. 🙁
import UIKit
import AVFoundation
class BossViewController: UIViewController {
var audioPlayer = AVAudioPlayer()
override func viewDidLoad() {
super.viewDidLoad()
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
}
//MARK: - Stop sound when we're change/close this viewController
override func viewWillDisappear(_ animated: Bool) {
super.viewWillDisappear(animated)
audioPlayer.stop()
}
This is how my button is look like:
#IBAction func boss1(_ sender: AnyObject) {
let audioFile = NSURL(fileURLWithPath: Bundle.main.path(forResource: "shamp", ofType: "mp3")!)
do {
audioPlayer = try AVAudioPlayer(contentsOf: audioFile as URL)
audioPlayer.prepareToPlay()
} catch {
print("Problem in getting File")
}
audioPlayer.play()
}
You can check if the audio player is playing, as #SandeepBhandari mentioned, or you can use a Bool variable to keep track whether or not the user tapped the button:
var buttonTapped = false
#IBAction func boss1(_ sender: AnyObject) {
...
buttonTapped = true
}
Then, you can check the variable in your viewWillDisappear(_ animated: Bool) method:
override func viewWillDisappear(_ animated: Bool) {
if buttonTapped {
audioPlayer.stop()
}
}
Related
I am creating a small project such that after pressing a button which
will take me to the next view controller using the navigation controller - can i delay the function to execute the navigation controller after some time
i am using this code-
import UIKit
class ViewController: UIViewController
{
#IBAction func enterButtonPressed(_ sender: UIButton)
{
let vc = storyboard?.instantiateViewController(withIdentifier: "ViewController2") as! ViewController2
self.navigationController?.pushViewController(vc, animated: true)
}
override func viewDidLoad()
{
super.viewDidLoad()
}
override func didReceiveMemoryWarning()
{
super.didReceiveMemoryWarning()
}
}
Suppose sender.tag holds the duration which is 0 for proceed , 5 or 10
var playTimer:Timer?
//
#IBAction func btnClicked(_ sender:UIButton) {
playTimer?.invalidate()
playTimer = Timer.scheduledTimer(withTimeInterval: TimeInterval(sender.tag), repeats: false, block: { (T) in
// play the audio
})
}
Try this one
var timeLimit = 5.0
DispatchQueue.main.asyncAfter(deadline: .now() + timeLimit, execute: {
//Play your audio here
//Audio will play after 5 seconds here
})
Im currently using 'AVKit' and 'AVFoundation' to enable the video playing through my app but I can only done by starting the video by tapping a button. But I am currently facing a problem of trying to making an automatic function like playing the video footage right after we start an app on an iOS device.
override func viewDidLoad()
{
super.viewDidLoad()
self.playingVideo()
self.nowPlaying(self)
}
#IBAction func nowPlaying(_ sender: Any)
{
self.present(self.playerController, animated: true, completion:{
self.playerController.player?.play()
})
after I compiled it, the system printed out:
Warning: Attempt to present on whose view is not in the window hierarchy!
Please try following working code.
import AVFoundation
import UIKit
class SomeViewController: UIViewController {
func openVideo() {
let playerController = SomeMediaPlayer()
playerController.audioURL = URL(string: "Some audio/video url string")
self.present(playerController, animated: true, completion: nil)
}
}
class SomeMediaPlayer: UIViewController {
public var audioURL:URL!
private var player = AVPlayer()
private var playerLayer: AVPlayerLayer!
override func viewDidLoad() {
super.viewDidLoad()
self.playerLayer = AVPlayerLayer(player: self.player)
self.view.layer.insertSublayer(self.playerLayer, at: 0)
let playerItem = AVPlayerItem(url: self.audioURL)
self.player.replaceCurrentItem(with: playerItem)
}
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
self.player.play()
}
override func viewWillLayoutSubviews() {
super.viewWillLayoutSubviews()
self.playerLayer.frame = self.view.bounds
}
// Force the view into landscape mode if you need to
override var supportedInterfaceOrientations: UIInterfaceOrientationMask {
get {
return .landscape
}
}
}
I created the button with Image on MainStoryBoard. When I press that button it plays audio file.
I would like that button to stay highlighted during the time audio file is playing. When the audio is finished, I want the button to return to its default state.
I discovered that audioPlayerDidFinishPlaying(_:successfully:) is a right way, but can not solve this problem. Is it close to the proper way to do it? If not, how should I?
I'd appreciate any advice that will lead to finding the solution to this problem. Thanks.
let url = Bundle.main.bundleURL.appendingPathComponent("audio1.mp3")
override func viewDidLoad() {
super.viewDidLoad()
}
func play(url: URL) {
do {
try player = AVAudioPlayer(contentsOf:url)
player.play()
} catch {
print(error)
}
}
#IBAction func pushButton1(sender: UIButton) {
play(url: url)
}
On viewDidLoad, you can set default property when it is not playing (eg: I'm keeping background color as white) and while playing, make that button as selected(eg: I'm making it color Green)
Again in audioPlayerDidFinishPlaying when it stops playing audio, make it to default state (green to white again):
#IBOutlet weak var yourButton: UIButton!
let url = Bundle.main.bundleURL.appendingPathComponent("audio1.mp3")
override func viewDidLoad() {
super.viewDidLoad()
self.yourButton.backgroundColor = UIColor.white // default state of button
}
#IBAction func pushButton1(sender: UIButton) {
play(url: url)
}
func play(url: URL) {
do {
try player = AVAudioPlayer(contentsOf:url)
player.play()
self.yourButton.backgroundColor = UIColor.green // playing
}
catch {
print(error)
}
}
func audioPlayerDidFinishPlaying(player: AVAudioPlayer!, successfully flag: Bool) {
self.yourButton.backgroundColor = UIColor.white // back to default state
}
I'm new to Swift and am trying to add a video to the view and then remove it when my "stopScreenSaver" notification is dispatched. All seems to work well except for when I go to remove the video layer (playerLayer.removeFromSuperlayer()).
Any guidance would be appreciated. I feel like I'm missing some basic concept here for adding and removing the layer!
import UIKit
import AVFoundation
import QuartzCore
import CoreMedia
class ViewController: UIViewController {
let contentURL = NSBundle.mainBundle().URLForResource("testvideo", withExtension: "mp4")
var player = AVPlayer()
var playerLayer = AVPlayerLayer()
let screenSize : CGRect = UIScreen.mainScreen().bounds
override func viewDidLoad() {
super.viewDidLoad()
// Used for starting and stopping the videos related to the screen saver
NSNotificationCenter.defaultCenter().addObserver(self, selector: "playScreenSaver:", name: "playScreenSaverID", object: nil)
NSNotificationCenter.defaultCenter().addObserver(self, selector: "stopScreenSaver:", name: "stopScreenSaverID", object: nil)
}
override func viewDidAppear(animated: Bool) {
// Player
player = AVPlayer(URL: contentURL!)
// Layer for display… Video plays at the full size of the iPad
playerLayer = AVPlayerLayer(player: player)
var view = UIView(frame: CGRectMake(0, 0, screenSize.width, screenSize.height))
self.view.layer.addSublayer(playerLayer)
playerLayer.frame = view.bounds
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
}
func playScreenSaver(notification: NSNotification){
print("play")
dispatch_async(dispatch_get_main_queue()) {
self.view.layer.addSublayer(self.playerLayer!)
self.player!.play()
}
}
func stopScreenSaver(notification: NSNotification){
print("pause")
dispatch_async(dispatch_get_main_queue()) {
self.player!.pause()
self.playerLayer!.removeFromSuperlayer()
}
}
}
Using the dispatch fixed the issue I was having.
dispatch_async(dispatch_get_main_queue()) {
self.player!.pause()
self.playerLayer!.removeFromSuperlayer()
}
override func viewWillDisappear(_ animated: Bool) {
super.viewWillDisappear(animated)
DispatchQueue.main.async {
self.player.currentItem?.removeObserver(self, forKeyPath: "duration", context: nil)
self.player!.pause()
self.playerLayer!.removeFromSuperlayer()
}
}
Try this
override func viewWillDisappear(_ animated: Bool) {
super.viewWillDisappear(animated)
DispatchQueue.main.async {
self.player?.pause()
self.playerLayer?.removeFromSuperlayer()
}
}
Please see below code. I am trying to remove the video subview from view when the 'done' button is pressed or video stops playing. I show no errors in the code but the removeFromSubview method does not seem to be working. I am not sure if my syntax is wrong or if it is something to do with having the movieplayer code within the IBAction method and the moviePlayBackDidFinish outside below the viewDidLoad. Any advise much appreciated. Thanks
import Foundation
import UIKit
import MediaPlayer
class VideoViewController: UIViewController {
var moviePlayer:MPMoviePlayerController!
#IBAction func videoLaunch(sender: AnyObject) {
playVideo()
}
func playVideo() {
let path = NSBundle.mainBundle().pathForResource("MyVideo", ofType:"mp4")
let url = NSURL.fileURLWithPath(path!)
moviePlayer = MPMoviePlayerController(contentURL: url)
if let player = moviePlayer {
player.view.frame = self.view.bounds
moviePlayer?.controlStyle = MPMovieControlStyle.Fullscreen
player.prepareToPlay()
self.view.addSubview(player.view)
}
}
override func viewDidLoad() {
super.viewDidLoad()
NSNotificationCenter.defaultCenter().addObserver(
self,
selector: "moviePlayBackDidFinish:",
name: MPMoviePlayerPlaybackDidFinishNotification,
object: moviePlayer)
func moviePlayBackDidFinish(notification: NSNotification){
self.view.removeFromSuperview()
}
}
}
You are trying to remove self.view not moviePlayer.view.
Change your moviePlayBackDidFinish code to:
func moviePlayBackDidFinish(notification: NSNotification)
{
if let player = moviePlayer
{
player.view.removeFromSuperview()
}
}