将 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
此扩展是为labelForID
和labelForValue
获得不同大小的字体所必需的
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) -> 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