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

Posted

技术标签:

【中文标题】将 UILabel 添加到子视图后如何重写它?【英文标题】:How do I rewrite a UILabel after it is added to a subView? 【发布时间】:2016-12-14 08:55:38 【问题描述】:

问题现已解决。 This answer 展示了一个基于工作解决方案的音频应用程序。

初始问题

我是 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 的扩展名,用于更改字体大小。

Thank you PiyushRathiand dijipiji


最终编辑

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 获得不同大小的字体所必需的

thank you Oleg Sherman

import UIKit

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

边缘条件

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

【问题讨论】:

我认为您需要在标签中显示滑块更改的值? 在你的代码中,当滑块值改变时,你直接将字符串赋值给lableForValue,这是你添加到View的最后一个标签,你需要先根据滑块标签取Label,然后赋值给它串起来。 @PiyushRathi,Piyush,我想你已经发现了问题所在。查看我的编辑,如果您提交带有解决方案的答案,我将接受它。谢谢 【参考方案1】:

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

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

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

    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)
            
        
    

希望这会有所帮助。

【讨论】:

太棒了!它使用 subview.tag / 1000 而不是 subview.tag % 1000 可以完美运行。这是公认的答案。非常感谢。 我发现了一个边缘条件,但它现在已修复 - 除第一个滑块外,所有滑块都更改了它们的值。修复方法是在写入标签时添加 1000 作为偏移量,并在读取标签时减去偏移量 func sliderValueChanged(sender: UISlider) 我已经添加了音频应用程序。你可能会感兴趣。 ***.com/q/41138367/2348597【参考方案2】:

看起来你有这些成员变量: var labelForValue:UILabel! var labelForID: UILabel!

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

注意 - 您将“标签”拼写为“标签”很多:)

【讨论】:

您需要通过 UISlider 作为参数发送,如下所示: 您需要通过 UISlider 作为参数发送,如下所示:slider.addTarget(self, action: #selector(sliderValueChanged(_:)), for: UIControlEvents.valueChanged) 尝试:slider.addTarget(self, action: #selector(sliderValueChanged(sender:)), for: UIControlEvents.valueChanged) 或者在 sliderValueChanged 中做:func sliderValueChanged(_ sender: UISlider) 使其成为可选 dijipiji,查看我的最新编辑。 Piyush 可能已经发现了问题所在。如果您也想提交带有解决方案的答案,我会接受。 SO 版主已要求将我们的讨论移至聊天,但我认为这没有必要。谢谢你们的cmets。他们很有帮助。【参考方案3】:

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

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

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
    

扩展 1 UILabel+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!
    

【讨论】:

以上是关于将 UILabel 添加到子视图后如何重写它?的主要内容,如果未能解决你的问题,请参考以下文章

将 UILabel 粘贴到 UIView 或 UIImageView

在子视图中像选框一样滚动 UILabel

将视图添加到子视图

将 UIViewController 的 UI 扩展到子 UIViewControllers

WKWebView 添加到子视图

如何将数组发送到子视图然后打印到标签中?