Search code examples
iosswiftuislidervoiceover

How to create a left/right audio balance slider and have Voiceover read out custom values?


I created an UISlider in Interface Builder, and want to use that to adjust the L/R audio volume balance between the two channels. This is what it looks like now:  enter image description here My current code is as follows:

import UIKit

class StreamBalanceTableViewCell: AudioStreamTableViewCell {
static let identifier = "StreamBalanceTableViewCell"

override func awakeFromNib() {
    super.awakeFromNib()

    self.slider.minimumTrackTintColor = .gray
    self.slider.maximumTrackTintColor = .gray
}

@IBOutlet var slider: UISlider!
override func updateUI() {
    self.slider.value = self.audioInterface?.balance ?? 0.0
    self.slider.isEnabled = !(self.audioInterface?.muted ?? true)
}


@IBAction func sliderChanged(_ slider: UISlider) {
    self.audioInterface?.balance = slider.value
}

}

Within Interface Builder, I set the slider value to 0, the minimum to -1 and the maximum to 1, and set the 'User Interaction Enabled', 'Adjustable', and 'Allows Direct Interaction' traits. BUT when I turn Voiceover on, I get values reported in 10% increments, starting at “50%”.

I’d like the slider to behave as it does in this view from the General > Accessibility Settings screen:

enter image description here

In this position, Voiceover reads: “30% left, 70% right”

How do I accomplish what I'm after?

Thanks!!!


Solution

  • You can set the values that VoiceOver speaks with the view properties(via NSObject):

    • .accessibilityLabel
    • .accessibilityHint
    • .accessibilityValue

    VoiceOver will speak a slider's .accessibilityValue as the slider moves.

    I set the slider to have a min of 0 and a max of 1 so that the value is in percentages, e.g. 0.35 is equivalent to 35%. Then I rounded off to the nearest 10%, so that VoiceOver would speak values like 70% left 30% right as the slider moved.

    import UIKit
    
    class ViewController: UIViewController {
    
        @IBOutlet var slider: UISlider!
    
        override func viewDidLoad() {
            super.viewDidLoad()
            // Do any additional setup after loading the view, typically from a nib.
    
            setSliderAccessibilityValue()           
        }
    
        @IBAction func sliderMoved(sender: Any?) {
            setSliderAccessibilityValue()    
        }
    
        func setSliderAccessibilityValue() {
    
            let right_percent = Int(
                round(slider.value * 10)  //=> round(0.2632 * 10) => round(2.632) => 3
            ) * 10  //=> 30
                                                    //       30% = right %
            let left_percent = 100 - right_percent  //        |
                                                    // left|..V......|right
                                                    // balance: 70% left, 30% right
            let accValue = "\(left_percent)% left \(right_percent)% right"           
            slider.accessibilityValue = accValue
    
        }
    
        override func didReceiveMemoryWarning() {
            super.didReceiveMemoryWarning()
            // Dispose of any resources that can be recreated.
        }
    }