I have a UIScrollView setup but when I change view the music doesn't stop. How do I make it so the music stops when you change view?
override func viewDidAppear(_ animated: Bool) {
super.viewDidAppear( animated)
meditationState = .on
setTrackForPlayerWith(trackName: "Bigsur")
player.play()
player.numberOfLoops = -1
}
Here is the whole class from viewcontroller.swift. I've added the func scrollViewDidScroll and the self part that you mentioned but it's still not working.
import UIKit
class ViewController: UIViewController, UIScrollViewDelegate {
@IBOutlet weak var scrollView: UIScrollView!
override func viewDidLoad() {
super.viewDidLoad()
let vc0 = ViewController0(nibName: "ViewController0", bundle: nil)
var frame0 = vc0.view.frame
frame0.origin.x = self.view.frame.size.width
vc0.view.frame = frame0
self.addChildViewController(vc0)
self.scrollView.addSubview(vc0.view)
vc0.didMove(toParentViewController: self)
let vc1 = ViewController1(nibName: "ViewController1", bundle: nil)
var frame1 = vc1.view.frame
frame1.origin.x = self.view.frame.size.width
vc1.view.frame = frame1
self.addChildViewController(vc1)
self.scrollView.addSubview(vc1.view)
vc1.didMove(toParentViewController: self)
let vc2 = ViewController2(nibName: "ViewController2", bundle: nil)
var frame2 = vc2.view.frame
frame2.origin.x = self.view.frame.size.width * 2
vc2.view.frame = frame2
self.addChildViewController(vc2)
self.scrollView.addSubview(vc2.view)
vc2.didMove(toParentViewController: self)
let vc3 = ViewController3(nibName: "ViewController3", bundle: nil)
var frame3 = vc3.view.frame
frame3.origin.x = self.view.frame.size.width * 3
vc1.view.frame = frame3
self.addChildViewController(vc3)
self.scrollView.addSubview(vc3.view)
vc3.didMove(toParentViewController: self)
self.scrollView.contentSize = CGSize(width: Double(self.view.frame.size.width * 4), height: Double(self.view.frame.size.height - 66))
self.scrollView.delegate = self
}
func scrollViewDidScroll(_ scrollView: UIScrollView) {
if scrollView.contentOffset.x > self.view.frame.size.x {
player.stop()
}
}
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
}
ViewController3 where 'player' is declared:
import UIKit
import AVFoundation
enum MeditationState {
case on
case off
}
class ViewController3: UIViewController {
var player:AVAudioPlayer = AVAudioPlayer()
var player1:AVAudioPlayer = AVAudioPlayer()
var meditationState: MeditationState?
var replicatorLayer = CAReplicatorLayer()
var dot = CALayer()
func updateTimer(){
seconds += 1
timerclock.text = "\(seconds)"
}
// Animation starts running
func animation2() {
// A layer that creates a specified number of copies of its sublayers (the source layer), each copy potentially having geometric, temporal, and color transformations applied to it.
replicatorLayer = CAReplicatorLayer()
// The layer’s bounds rectangle. Animatable.
replicatorLayer.bounds = CGRect(x: 0.0, y: 0.0, width: 300.0, height: 300.0)
// The radius to use when drawing rounded corners for the layer’s background. Animatable.
replicatorLayer.cornerRadius = 10.0
// The background color of the receiver. Animatable.
replicatorLayer.backgroundColor = UIColor(white: 0.0, alpha: 0.0).cgColor
// The layer’s position in its superlayer’s coordinate space. Animatable.
replicatorLayer.position = view.center
// calling this method creates an array for that property and adds the specified layer to it.
view.layer.addSublayer(replicatorLayer)
// connectng the animation to the content
// An object that manages image-based content and allows you to perform animations on that content
dot = CALayer()
// The layer’s bounds rectangle. Animatable.
dot.bounds = CGRect(x: 0.0, y: 0.0, width: 12.0, height: 12.0)
//The layer’s position in its superlayer’s coordinate space. Animatable.
dot.position = CGPoint(x: 150.0, y: 40.0)
//The background color of the receiver. Animatable.
dot.backgroundColor = UIColor(white: 0.2, alpha: 1.0).cgColor
// The color of the layer’s border. Animatable.
dot.borderColor = UIColor(white: 1.0, alpha: 1.0).cgColor
// The width of the layer’s border. Animatable.
dot.borderWidth = 1.0
//The radius to use when drawing rounded corners for the layer’s background. Animatable.
dot.cornerRadius = 5.0
//Appends the layer to the layer’s list of sublayers.
replicatorLayer.addSublayer(dot)
// number of copies of layer is instanceCount
let nrDots: Int = 1000
//The number of copies to create, including the source layers.
replicatorLayer.instanceCount = nrDots
// The basic type for floating-point scalar values in Core Graphics and related frameworks.
let angle = CGFloat(2*M_PI) / CGFloat(nrDots)
// The transform matrix applied to the previous instance to produce the current instance. Animatable.
replicatorLayer.instanceTransform = CATransform3DMakeRotation(angle, 0.0, 0.0, 1.0)
// Type used to represent elapsed time in seconds.
let duration: CFTimeInterval = 10.0
// animation capabilities for a layer property.
// An object that provides basic, single-keyframe animation capabilities for a layer property.
let shrink = CABasicAnimation(keyPath: "transform.scale")
// Defines the value the receiver uses to start interpolation.
shrink.fromValue = 1.0
// Defines the value the receiver uses to end interpolation.
shrink.toValue = 0.1
// Specifies the basic duration of the animation, in seconds.
shrink.duration = duration
// Determines the number of times the animation will repeat.
shrink.repeatCount = Float.infinity
// Add the specified animation object to the layer’s render tree.
dot.add(shrink, forKey: "shrink")
// Specifies the delay, in seconds, between replicated copies. Animatable.
replicatorLayer.instanceDelay = duration/Double(nrDots)
// The transform applied to the layer’s contents. Animatable.
dot.transform = CATransform3DMakeScale(0.01, 0.01, 0.01)
}
// connecting the breathe in label
@IBOutlet weak var label: UILabel!
// instant delay
@IBOutlet weak var instantDelay: UIButton!
@IBAction func delayBtn(_ sender: Any) {
dot.removeAnimation(forKey: "shrink")
timer1.invalidate()
seconds = 0
timer2.invalidate()
timerclock.text = "\(seconds)"
time = 0
timerLabel.text = "Breathe in"
timerisOn = false
pauseBtn.isHidden = true
playBtn.isHidden = false
label.isHidden = true
replicatorLayer.isHidden = true
instantDelay.isHidden = true
instantDelay1.isHidden = false
slider.isHidden = false
}
// Delay 1
@IBOutlet weak var instantDelay1: UIButton!
@IBAction func delayBtn1(_ sender: Any) {
instantDelay1.isHidden = true
instantDelay.isHidden = false
label.isHidden = false
slider.isHidden = true
}
//Slider for changing animation speed
@IBOutlet weak var slider: UISlider!
@IBAction func slider(_ sender: Any) {
}
@IBAction func speed(_ sender: UISlider) {
view.layer.speed = sender.value
}
//Sound On button
@IBOutlet weak var soundOn: UIButton!
@IBAction func SoundOn(_ sender: Any) {
meditationState = .on
setTrackForPlayerWith(trackName: "Mute")
player.play()
soundoff.isHidden = false
soundOn.isHidden = true
}
//Sound Off button
@IBOutlet weak var soundoff: UIButton!
@IBAction func SoundOff(_ sender: Any) {
meditationState = .off
setTrackForPlayerWith(trackName: "Bigsur")
player.play()
soundoff.isHidden = true
soundOn.isHidden = false
}
//Timerclock at top of screen label
@IBOutlet weak var timerclock: UILabel!
// creating vars to set things
var animation = CFTimeInterval()
var timer1 = Timer()
var timer2 = Timer()
var time = 0
var seconds = 0
var timerisOn = false
// connecting breathe in label
@IBOutlet var question: UILabel!
var arrayOfStrings: [String] = [""]
// connecting timerclick and starting it
@IBOutlet var timerLabel: UILabel!
// changes the amount of time on the label of different labels
func increaseTimer() {
time += 1
switch time {
case 0 ... 7:
timerLabel.text = "Hold"
case 8 ... 10:
timerLabel.text = "Breathe Out"
case 11 ... 12:
timerLabel.text = "Breathe in"
default:
time = 0
}
}
// connecting the play button and vars
@IBOutlet weak var playBtn: UIButton!
@IBAction func play(sender: AnyObject) {
bell(trackName: "Bell")
player1.play()
timer1 = Timer.scheduledTimer(timeInterval: 1, target: self, selector: #selector(ViewController3.increaseTimer), userInfo: nil, repeats: true)
pauseBtn.isHidden = false
playBtn.isHidden = true
if timerisOn == false {
timer2 = Timer.scheduledTimer(timeInterval: 1, target: self, selector: #selector(updateTimer), userInfo: nil, repeats: true)
timerisOn = true
}
animation2()
}
// pausing the timer with the vars
@IBOutlet weak var pauseBtn: UIButton!
@IBAction func pause(sender: AnyObject) {
dot.removeAnimation(forKey: "shrink")
timer1.invalidate()
seconds = 0
timer2.invalidate()
timerclock.text = "\(seconds)"
time = 0
timerLabel.text = "Breathe in"
timerisOn = false
pauseBtn.isHidden = true
playBtn.isHidden = false
}
override func viewDidAppear(_ animated: Bool) {
super.viewDidAppear( animated)
meditationState = .on
setTrackForPlayerWith(trackName: "Bigsur")
player.play()
player.numberOfLoops = -1
}
override func viewDidLoad() {
super.viewDidLoad()
time += 1
do {
try AVAudioSession.sharedInstance().setCategory(AVAudioSessionCategoryAmbient)
print("AVAudioSession Category Playback OK")
do {
try AVAudioSession.sharedInstance().setActive(true)
print("AVAudioSession is Active")
} catch let error as NSError {
print(error.localizedDescription)
}
} catch let error as NSError {
print(error.localizedDescription)
}
}
func setTrackForPlayerWith(trackName: String) {
do
{
let audioPath = Bundle.main.path(forResource: trackName, ofType: "mp3")
try player = AVAudioPlayer(contentsOf: NSURL(fileURLWithPath: audioPath!) as URL)
}
catch
{
//ERROR
}
}
func bell(trackName: String) {
do
{
let audioPath = Bundle.main.path(forResource: trackName, ofType: "mp3")
try player1 = AVAudioPlayer(contentsOf: NSURL(fileURLWithPath: audioPath!) as URL)
}
catch
{
//ERROR
}
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
}
You can observe the changes made in your UIScrollView
subclass in various delegate methods.
First of all, lets make sure your scrollView's delegate is assigned to the viewController. To do so, one option is to add following to viewDidLoad()
// `scrollView` should be whatever is your scrollView called in your VC
self.scrollView.delegate = self
Once this is done, lets make your UIViewController
subclass conform to UIScrollViewDelegate
class ViewController: UIViewController, UIScrollViewDelegate {
func scrollViewDidScroll(_ scrollView: UIScrollView) {
if scrollView.contentOffset.x > self.view.frame.size.x {
player.stop()
}
}
}
UIScrollViewDelegate
has numerous methods to observe changes in your scrollView. scrollViewDidScroll(_:)
will be called every time there is an interaction with the scrollView, so as soon as the contentOffset
is greater than the width of the view, lets stop the music.