【问题标题】:Change views on UIScrollView so music changes更改 UIScrollView 上的视图,以便音乐更改
【发布时间】:2017-06-01 22:46:35
【问题描述】:

我有一个 UIScrollView 设置,但是当我改变视图时,音乐并没有停止。我如何做到让你改变视图时音乐停止?

override func viewDidAppear(_ animated: Bool) {
    super.viewDidAppear( animated)
    meditationState = .on
    setTrackForPlayerWith(trackName: "Bigsur")
    player.play()
    player.numberOfLoops = -1

}

这是来自 viewcontroller.swift 的整个类。我已经添加了你提到的 func scrollViewDidScroll 和 self 部分,但它仍然无法正常工作。

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:

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.
    }



}

【问题讨论】:

  • 更改视图是指更改viewController,还是滚动到scrollView上的新视图?
  • 在滚动视图上滚动到新视图
  • 你知道视图的宽度是多少吗?
  • 不确定,为什么要问?
  • 视图总是和屏幕一样宽吗?它覆盖整个屏幕吗?也许截图会有所帮助。

标签: ios xcode uiscrollview swift3 avaudioplayer


【解决方案1】:

您在寻找viewWillDisappear(_:) 吗?在该方法中,您只需添加 player.stop() 即可在您更改视图时停止播放音乐。

【讨论】:

  • 我添加了: override func viewWillDisappear(_ animated: Bool) { player.stop() }
  • 但是还是不行。当您更改视图时,您向右滑动,当您这样做时,音乐仍然打开。如果您对如何解决它有任何其他想法,请告诉我?
  • 我意识到 viewWillDisappear 由于某种原因没有被调用
  • 内德 - 你忘了代表
【解决方案2】:

做到这一点的聪明方法就是......

假设它是一个垂直表。

1. 每个表格视图单元格都有与之关联的音轨。想想一个特定的单元 - C - 它有一个音轨 A。

2. 当视图滚动时(即,每当它移动时),只需获取 C 的框架

3. 只取高度。然后取屏幕 SH 的高度。然后得到C到屏幕中心的距离......所以Abs(SH - H)。然后将该数字作为 SH 的一部分(零到一)。所以,Abs(SH - H)/H

(根据您的情况,最好除以单元格的高度,而不是屏幕高度。)

4. 现在...只需将所有音轨 A 的音量设置为该分数。事实上,只需对每个单元格执行此操作即可。

当您滚动时,音频将在各个轨道之间混合。

“魔法”:)

【讨论】:

    【解决方案3】:

    您可以在各种委托方法中观察您的 UIScrollView 子类中所做的更改。

    首先,让我们确保您的滚动视图的委托已分配给视图控制器。为此,一种选择是将关注添加到viewDidLoad()

    // `scrollView` should be whatever is your scrollView called in your VC
    self.scrollView.delegate = self
    

    完成后,让您的UIViewController 子类符合UIScrollViewDelegate

    class ViewController: UIViewController, UIScrollViewDelegate {
    
        func scrollViewDidScroll(_ scrollView: UIScrollView) {
            if scrollView.contentOffset.x > self.view.frame.size.x {
                player.stop()
            }
        }
    }
    

    UIScrollViewDelegate 有许多方法可以观察滚动视图的变化。 scrollViewDidScroll(_:) 会在每次与 scrollView 交互时被调用,所以只要 contentOffset 大于视图的宽度,就让音乐停止。

    【讨论】:

    • 我应该把它放在链接到屏幕或单个屏幕的主视图控制器中。我把'self.scrollView.delegate = self'放在主视图控制器中,它说它不能为类型viewcontroller分配值来输入uiviewdelegate?然后,如果我尝试将其放在单个视图控制器中,它会显示:“viewcontroller3”类型的值没有成员“scrollview”我现在该怎么办?
    • 你的 scrollView 是在哪里定义的?它应该进入那个 ViewController。
    • scrollView 在主视图控制器中被称为scrollView:@IBOutlet weak var scrollView: UIScrollView!
    • 应该去那里。当您输入该行时,您可能会收到错误,但不仅仅是我写的第二部分,错误应该得到解决。
    • 好的,我试试看。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2011-12-14
    • 1970-01-01
    • 1970-01-01
    • 2012-05-22
    • 1970-01-01
    • 2011-11-02
    • 1970-01-01
    相关资源
    最近更新 更多