将 UILabel 添加到子视图后如何重写它?

How do I rewrite a UILabel after it is added to a subView?

问题现已解决。 显示基于工作解决方案的音频应用程序。

初始问题

我是 Swift 的新手,正在尝试创建一组 UISliders 来测试 parameters of a physical model in AudioKit。每个 UISlider 有两个 UILabels,一个用于标识参数名称,另一个用于显示当前 UISlider 值。标签标识每个 UISlider 及其对应的 UIlabels.

尽管我可以在 Xcode 的调试区域中显示这些值,但我无法尝试在 iPhone 的相应 UILabel 中显示当前 UISlider 值。当我将 slider.value 写入它的 lableForValue 时,除了一个奇怪的边缘条件外什么都没有发生(见底部的图表)。

UISlider 值的日志清楚地表明它接收到发送的值并使用 sender.tag 识别哪个 UISlider 发送它。但是新值永远不会出现在正确的 UILabel.

解决方案

这是一个可行的解决方案,希望能使其他 Swift 新手受益。已根据已接受的答案对下面的代码 进行了更改。在将 lableForValue 添加到 subview 之前用标记偏移量标记 lableForValue 允许 UILabels 更容易识别并用从 UISlider. 读取的值重写 接受的答案也是一个简单的实际演示如何使用选项。已经确定了进一步的边缘条件 - UILabels 将显示除第一个滑块之外的所有滑块的值 - 并在最终编辑中更正。该代码还包括用于更改字体大小的 UILabel 扩展。


最终编辑

import UIKit

class ViewController: UIViewController {

var slider: UISlider!
var lableForValue: UILabel!
var lableForID: UILabel!

let defaultColour       = UIColor.green
let highlightedColour   = UIColor.lightGray

let thumbSize: CGFloat  = 20
let topMargin           = 75
let verticalSpacing     = 50
let sliderWidth         = 250
let sliderHeight        = 24
let sliderToLabelSpace  = 32

let valueLableTagOffset = 1000

let lables              = ["intensity", 
                           "dampingFactor", 
                           "energyReturn", 
                           "mainResFreq", 
                           "1stResFreq", 
                           "2ndResFreq", 
                           "amplitude", 
                           "reserved", 
                           "reserved", 
                           "reserved"]

let loLimits            = [0,   0,   0,   0,   0,   0,   0,   0,   0,   0]
let hiLimits            = [100, 100, 100, 100, 100, 100, 100, 100, 100, 100]


override func viewDidLoad() {
    super.viewDidLoad()

    for index in 0..<10 {

        let slider      = makeSlider(index: index)
        let IDLable     = makeIDLable(index: index)
        let valueLable  = makeValueLable(index: index)

        view.addSubview(slider)
        view.addSubview(IDLable)
        view.addSubview(valueLable)
        }

    }


func sliderValueChanged(sender: UISlider){

print("SLIDER", sender.tag, ":", sender.value)

    var valueLabel: UILabel? = nil

    for subview in view.subviews as [UIView] {

        if subview.tag > valueLableTagOffset {
            print(subview.tag)

            let labelTag = subview.tag - valueLableTagOffset

     // Edge condition: UILabels display values for all sliders except the first 
     // Fix: use '- valueLableTagOffset', not '/ valueLableTagOffset'

            print(labelTag)

            if labelTag == sender.tag {

                valueLabel = subview as? UILabel
                break
            }
        }
    }

    if valueLabel != nil {
        valueLabel!.text = String(sender.value)
    }
}


func makeHighlightedImage() -> (UIImage) {
    let size                        = thumbSize
    let highlightedStateImage       = UIImage.createThumbImage(size: size, color: highlightedColour)
    return (highlightedStateImage)
    }

func makeDefaultImage() -> (UIImage) {
    let size                        = thumbSize
    let defaultStateImage           = UIImage.createThumbImage(size: size, color: defaultColour)
    return (defaultStateImage)
    }


func makeValueLable(index: Int) -> UILabel {
    let x                           = Int(view.frame.midX) - (sliderWidth / 2)
    let y                           = Int(topMargin + (verticalSpacing * index) - sliderToLabelSpace)
    let w                           = sliderWidth
    let h                           = sliderHeight

    lableForValue                   = UILabel(frame: CGRect(x: x, y: y, width: w, height: h))

    lableForValue.tag               = (index + 1) + valueLableTagOffset

     // Edge condition: UILabels display values for all sliders except the first 
     // Fix: use '+ valueLableTagOffset', not '* valueLableTagOffset'

    lableForValue.textColor         = defaultColour
    lableForValue.textAlignment     = NSTextAlignment.center
    lableForValue.text              = String(index + 1)
    return lableForValue
    }


func makeIDLable(index: Int) -> UILabel {
    let x                           = Int(view.frame.midX) - (sliderWidth / 2)
    let y                           = Int(topMargin + (verticalSpacing * index) - 32)
    let w                           = sliderWidth
    let h                           = sliderHeight

    lableForID                      = UILabel(frame: CGRect(x: x, y: y, width: w, height: h))
    lableForID.tag                  = index + 1
    lableForID.textColor            = highlightedColour
    lableForID.textAlignment        = NSTextAlignment.left
    lableForID.defaultFont          = UIFont(name: "HelveticaNeue", size: CGFloat(12))
    lableForID.text                 = lables[index]
    return lableForID
    }

func makeSlider(index: Int) -> UISlider {
    let x                           = view.frame.midX
    let y                           = CGFloat(topMargin + (verticalSpacing * index))
    let w                           = sliderWidth
    let h                           = sliderHeight

    slider                          = UISlider(frame: CGRect(x: 0, y: 0, width: w, height: h))
    slider.center                   = CGPoint(x: x, y: y)

    slider.minimumValue             = Float(loLimits[index])
    slider.minimumTrackTintColor    = defaultColour
    slider.maximumValue             = Float(hiLimits[index])
    slider.maximumTrackTintColor    = highlightedColour
    slider.tag                      = index + 1

    slider.value                    = slider.maximumValue / 2.0

    slider.isContinuous             = false
    slider.addTarget(self, action: #selector(sliderValueChanged), for: UIControlEvents.valueChanged)
    return slider
    }
}

UILabel+FontFiddler

此扩展是为 labelForIDlabelForValue

获取不同大小的字体所必需的

import UIKit

extension UILabel{
    var defaultFont: UIFont? {
        get { return self.font }
        set { self.font = newValue }
        }
    }

边缘条件

下面的屏幕截图显示了移动任何滑块时最后一个 UILabel 发生的情况。无论移动哪个滑块或移动多远,显示的值始终为 50.0。我确实知道,当我禁用从滑块 10 读取值的语句时,情况会消失。但是我不知道每当其他滑块移动时,滑块 10 的 UILabel 中的值 50 总是出现的原因。

看起来你有这些成员变量: var lableForValue:UILabel! var lableForID: UILabel!

在您的 func makeValueLable 中,您应该考虑创建一个新标签而不是引用成员变量。简而言之 - 放弃这些 UILabel 的成员变量,并在 makeValueLable 和 makeIDLabel 内部创建新实例: 让 labelForValue = UILabel() 让 lablelFotID = UILabel() 等等

请注意 - 您将 "label" 拼写为 "lable" 相当多:)

您好,您必须对代码进行几处更改:

  1. 您必须向每个 lableForValue 传递一个 unique tag 值,以便可以在 UIView 中轻松找到它。

    例如为了 在 func makeValueLable(index: Int) -> UILabel 函数中添加标签 put lableForValue.tag = (index + 1) * 1000

  2. func sliderValueChanged(sender: UISlider){改为:

    func sliderValueChanged(sender: UISlider) {
    
            var valueLabel:UILabel? = nil;
            for subview in view.subviews as [UIView] {
                if subview.tag > 1000 {
    
                    let labelTag = subview.tag / 1000
                    if labelTag == sender.tag {
                        valueLabel = subview as? UILabel
                        break
                    }
                }
            }
            if valueLabel != nil {
                valueLabel!.text = String(sender.value)
            }
        }
    

希望这对您有所帮助。

以下是如何使用 UISliders 更改物理建模音频合成中的参数。您将需要 AudioKit.framework. 下载和使用说明可以在 here 中找到。

该模型本质上是一个混沌系统,用于合成滴水发出的声音。有些滑块比其他滑块更有效,但 dampingFactor 激发了物理模型。起初,当这个改变时,可以听到孤立的滴水声,但是,就像标准的管道装置一样,如果你 fiddle 使用它足够长的时间,你会听到稳定的滴水声,这可能很难(但并非不可能)停止。共振频率的三个滑块会影响声音的音调。

import UIKit
import AudioKit

class ViewController: UIViewController {

let drip            = AKDrip()
var timer           = Timer()

var slider: UISlider!
var lableForValue: UILabel!
var lableForID: UILabel!

let defaultColour       = UIColor.green
let highlightedColour   = UIColor.lightGray

let thumbSize: CGFloat  = 20
let topMargin           = 75
let verticalSpacing     = 50
let sliderWidth         = 250
let sliderHeight        = 24
let sliderToLabelSpace  = 38

let valueLableTagOffset = 1000

let lables              = ["intensity",
                           "dampingFactor",
                           "energyReturn",
                           "mainResFreq",
                           "1stResFreq",
                           "2ndResFreq",
                           "amplitude",
                           "rampTime",
                           "reserved",
                           "reserved"]

let loLimits            = [0,     0,     0,     0,      0,      0,      0,     0,     0,    0]
let hiLimits            = [100,   100,   100,   1000,   1000,   1000,   100,   100,   100,  100]
//                        [10.0,  2.9,   5.0,   750.0,  450.0,  600.0,  0.5,   1.0,   0,    0]


override func viewDidLoad() {
    super.viewDidLoad()

    for index in 0..<10 {

        let slider      = makeSlider(index: index)
        let IDLable     = makeIDLable(index: index)
        let valueLable  = makeValueLable(index: index)

        view.addSubview(slider)
        view.addSubview(IDLable)
        view.addSubview(valueLable)

    }

    // Physical Model Oscillator

    AudioKit.output = drip
    AudioKit.start()

    drip.start()        
}


func sliderValueChanged(sender: UISlider){

    print("SLIDER", sender.tag, ":", sender.value)

    var valueLabel: UILabel? = nil                              // clear UILabel

    for subview in view.subviews as [UIView] {                  // find all subviews including labels

        if subview.tag > valueLableTagOffset {                  // identify labels that show values
            print(subview.tag)

            let labelTag = subview.tag - valueLableTagOffset    // get true tag by removing offset
            print(labelTag)

            if labelTag == sender.tag {                         // does tag match the slider that moved ?

                valueLabel = subview as? UILabel                // then this subview is the value label

                break
            }
        }
    }

    if valueLabel != nil {
        valueLabel!.text    = String(sender.value)              // so write slider value into its label
        let paramValue      = sender.value
        let paramID         = sender.tag
        setDrip(paramValue: paramValue, paramID: paramID)       // and write slider value into parameter
        }
    }

func setDrip(paramValue: Float, paramID: Int) {
    switch paramID {
    case 0:
        drip.intensity                  = Double(paramValue)    //10
    case 1:
        drip.dampingFactor              = Double(paramValue)    //2.9
    case 2:
        drip.energyReturn               = Double(paramValue)    //5
    case 3:
        drip.mainResonantFrequency      = Double(paramValue)    //750
    case 4:
        drip.firstResonantFrequency     = Double(paramValue)    //450
    case 5:
        drip.secondResonantFrequency    = Double(paramValue)    //600
    case 6:
        drip.amplitude                  = Double(paramValue)    //0.5
    case 7:
        drip.rampTime                   = Double(paramValue)    //1.0

    default:
        print("nothing to change for sliders 8 & 9")
        }    
    }


func makeHighlightedImage() -> (UIImage)    {
    let size                        = thumbSize
    let highlightedStateImage       = UIImage.createThumbImage(size: size, color: highlightedColour)
    return (highlightedStateImage)
    }

func makeDefaultImage() -> (UIImage)        {
    let size                        = thumbSize
    let defaultStateImage           = UIImage.createThumbImage(size: size, color: defaultColour)
    return (defaultStateImage)
}


func makeValueLable(index: Int) -> UILabel  {
    let x                           = Int(view.frame.midX) - (sliderWidth / 2)
    let y                           = Int(topMargin + (verticalSpacing * index) - sliderToLabelSpace)
    let w                           = sliderWidth
    let h                           = sliderHeight

    lableForValue                   = UILabel(frame: CGRect(x: x, y: y, width: w, height: h))
    lableForValue.tag               = (index + 1) + valueLableTagOffset
    lableForValue.textColor         = defaultColour
    lableForValue.textAlignment     = NSTextAlignment.center
    lableForValue.text              = String(index + 1)
    return lableForValue
    }

func makeIDLable(index: Int) -> UILabel     {
    let x                           = Int(view.frame.midX) - (sliderWidth / 2)
    let y                           = Int(topMargin + (verticalSpacing * index) - 32)
    let w                           = sliderWidth
    let h                           = sliderHeight

    lableForID                      = UILabel(frame: CGRect(x: x, y: y, width: w, height: h))
    lableForID.tag                  = index + 1
    lableForID.textColor            = highlightedColour
    lableForID.textAlignment        = NSTextAlignment.left
    lableForID.defaultFont          = UIFont(name: "HelveticaNeue", size: CGFloat(12))
    lableForID.text                 = lables[index]
    return lableForID
    }

func makeSlider(index: Int) -> UISlider     {
    let x                           = view.frame.midX
    let y                           = CGFloat(topMargin + (verticalSpacing * index))
    let w                           = sliderWidth
    let h                           = sliderHeight

    slider                          = UISlider(frame: CGRect(x: 0, y: 0, width: w, height: h))
    slider.center                   = CGPoint(x: x, y: y)

    slider.minimumValue             = Float(loLimits[index])
    slider.minimumTrackTintColor    = defaultColour
    slider.maximumValue             = Float(hiLimits[index])
    slider.maximumTrackTintColor    = highlightedColour
    slider.tag                      = index + 1

    if (lables[index] != "reserved") {

        slider.value                = slider.maximumValue / 2.0
        slider.isContinuous         = false
        slider.addTarget(self, action: #selector(sliderValueChanged), for: UIControlEvents.valueChanged)

    } else {
        slider.value                = 0
    }
    return slider
    }
}

扩展 1UILabel+FontFiddler

import UIKit

extension UILabel{
var defaultFont: UIFont? {
    get { return self.font }
    set { self.font = newValue }
    }
}

扩展2 UIImage+DrawCircle

Thank you McMatan

import UIKit

extension UIImage {

class func createThumbImage(size: CGFloat, color: UIColor) -> UIImage {

    let layerFrame          = CGRect(x: 0, y: 0, width: size, height: size)

    let shapeLayer          = CAShapeLayer()
    shapeLayer.path         = CGPath(ellipseIn: layerFrame.insetBy(dx: 1, dy: 1), transform: nil)
    shapeLayer.fillColor    = color.cgColor
    shapeLayer.strokeColor  = color.withAlphaComponent(0.65).cgColor

    let layer               = CALayer.init()
    layer.frame             = layerFrame
    layer.addSublayer(shapeLayer)
    return self.imageFromLayer(layer: layer)

}

class func imageFromLayer(layer: CALayer) -> UIImage {

    UIGraphicsBeginImageContextWithOptions(layer.frame.size, false, UIScreen.main.scale)
    layer.render(in: UIGraphicsGetCurrentContext()!)
    let outputImage         = UIGraphicsGetImageFromCurrentImageContext()
    UIGraphicsEndImageContext()
    return outputImage!
    }
}