Swift: 更改 UIView 框架但显示不更新
Swift: Changing UIView frame but display doesn't update
我正在尝试动态调整 UIView 框架的大小。我可以更新代码中的框架并看到值已经改变,但实际显示永远不会改变,即使我 运行 setNeedsDisplay().
我正在关注 ,我通过 CGRectMake 定义了一个新框架,然后将 UIView 的框架设置为这个新框架。即,我正在这样做...
let newFrame = CGRectMake(minX,minY, width, height)
VUBarCover.frame = newFrame
如果我打印出 UIView 框架的值,我会看到它正在按我喜欢的方式变化。但是显示(在模拟器中)从不反映这些变化。
知道如何解决这个问题吗?
更新: 更详细地说:我试图以编程方式用一个 UIView 覆盖另一个。它是一个水平 "VU Meter",由一个显示颜色渐变的基础 UIImageView 组成,它由一个黑色背景的 UIView 部分动态 "covered" 向上。
UIImageView "VUBarImageView" 在 StoryBoard 中定义,受 AutoLayout 约束。黑色 UIView "VUBarCover" 完全以编程方式定义,没有 AutoLayout 约束。
为了完整性,这里是代码的相关部分...我遇到的问题是 updateVUMeter()...
@IBOutlet weak var VUBarImageView: UIImageView!
var VUBarCover : UIView!
// this gets called after AutoLayout is finished
override func viewDidLayoutSubviews() {
// cover up VU Meter completely
let center = VUBarImageView.center
let width = VUBarImageView.frame.width
let height = VUBarImageView.frame.height
let frame = VUBarImageView.frame
VUBarCover = UIView(frame: frame)
MainView.addSubview(VUBarCover)
VUBarCover.backgroundColor = UIColor.blueColor() // use black eventually. blue lets us see it for testing
}
// partially cover up VUBarImage with black VUBarCover coming from the "right"
func updateVUMeter(inputValue:Float) { //inputValue is in dB
//let val = pow(10.0,inputValue/10) // convert from dB
let val = Float( Double(arc4random())/Double(UInt32.max) ) //for Simulator testing, just use random numbers between 0 and 1
print("val = ",val)
let fullWidth = VUBarImageView.frame.width
let maxX = VUBarImageView.frame.maxX
let width = fullWidth * CGFloat(1.0-val)
let minX = maxX - width
let minY = VUBarImageView.frame.minY
let height = VUBarImageView.frame.height
let newFrame = CGRectMake(minX,minY, width, height)
VUBarCover.frame = newFrame
VUBarCover.setNeedsDisplay()
print("fullWidth = ",fullWidth,"width = ",width)
print(" newFrame = ",newFrame,"VUBarCover.frame = ",VUBarCover.frame)
}
样本结果为:
val = 0.9177
fullWidth = 285.0 width = 23.4556210041046
newFrame = (278.544378995895, 93.5, 23.4556210041046, 10.0) VUBarCover.frame = (278.544378995895, 93.5, 23.4556210041046, 10.0)
val = 0.878985
fullWidth = 285.0 width = 34.4891595840454
newFrame = (267.510840415955, 93.5, 34.4891595840454, 10.0) VUBarCover.frame = (267.510840415955, 93.5, 34.4891595840454, 10.0)
val = 0.955011
fullWidth = 285.0 width = 12.8218790888786
newFrame = (289.178120911121, 93.5, 12.8218790888786, 10.0) VUBarCover.frame = (289.178120911121, 93.5, 12.8218790888786, 10.0)
...也就是说,我们看到 VUBarCover.frame 正在改变 'internally',但在屏幕上它永远不会改变。我们看到的是全尺寸封面,完全覆盖了下面的图像(大约 300 像素宽),尽管它的宽度应该只有大约 12 像素)。
即使我在 VUBarCover 的超级视图上执行 setNeedsDisplay(),也没有任何变化。
帮忙?谢谢。
首先,你有几个错误值得注意:
- 实例变量(如
VUBarCover
和 MainView
应始终以小写字母开头(如 mainView
)。
- 您应该在覆盖实施开始时调用
super.viewDidLayoutSubviews()
其次,viewDidLayoutSubviews()
可以被调用任意次数,所以你对这个方法的实现应该是idempotent,意思是无论调用多少次,效果都是一样的次它被称为。但是当你打电话时:
VUBarCover = UIView(frame: frame)
MainView.addSubview(VUBarCover)
您正在创建一个 new UIView
并将其添加到视图层次结构中,以及您过去可能添加的其他视图。所以它看起来 框架没有在屏幕上更新。事实上,您无法分辨,因为 旧 视图落后于您正在更新的视图,并且它们 没有改变。
相反,您可能想创建一次:
var vuBarCover = UIView()
将其添加为 viewDidLoad()
中的子视图:
mainView.addSubview(vuBarCover)
并在viewDidLayoutSubviews()
中修改其框架:
vuBarCover.frame = vuBarImageView.frame
您不需要致电 setNeedsDisplay()
。
我现在正在制作一个像你一样的自定义 UIView,也许我能帮上忙。
首先,viewDidLayoutSubviews()喜欢你的评论:这会在 AutoLayout 完成后调用。在每个布局都设置好之后,你开始为你的 UIView 和 UIImage 设置新的框架,也许错误就在这里。请尝试将 viewDidLayoutSubviews() 中的代码移动到 layoutSubviews()。并且不要忘记在覆盖函数中添加 super.layoutSubviews() ,这可以帮助您远离数百个错误:].
其次,仅当您覆盖 drawRect: 方法时,您才应该调用 setNeedsDisplay(),它告诉系统我需要重新绘制我的视图,系统将适当地调用 drawRect: 方法。
希望你能想通。
在我的例子中,层上留下了动画,删除它们后,帧更改会更新:
myView.layer.removeAllAnimations()
iOS 在屏幕上显示 UIView
的 presentationLayer
,动画在该层上播放(frame
更新在动画期间进行)。
我正在尝试动态调整 UIView 框架的大小。我可以更新代码中的框架并看到值已经改变,但实际显示永远不会改变,即使我 运行 setNeedsDisplay().
我正在关注
let newFrame = CGRectMake(minX,minY, width, height)
VUBarCover.frame = newFrame
如果我打印出 UIView 框架的值,我会看到它正在按我喜欢的方式变化。但是显示(在模拟器中)从不反映这些变化。
知道如何解决这个问题吗?
更新: 更详细地说:我试图以编程方式用一个 UIView 覆盖另一个。它是一个水平 "VU Meter",由一个显示颜色渐变的基础 UIImageView 组成,它由一个黑色背景的 UIView 部分动态 "covered" 向上。 UIImageView "VUBarImageView" 在 StoryBoard 中定义,受 AutoLayout 约束。黑色 UIView "VUBarCover" 完全以编程方式定义,没有 AutoLayout 约束。
为了完整性,这里是代码的相关部分...我遇到的问题是 updateVUMeter()...
@IBOutlet weak var VUBarImageView: UIImageView!
var VUBarCover : UIView!
// this gets called after AutoLayout is finished
override func viewDidLayoutSubviews() {
// cover up VU Meter completely
let center = VUBarImageView.center
let width = VUBarImageView.frame.width
let height = VUBarImageView.frame.height
let frame = VUBarImageView.frame
VUBarCover = UIView(frame: frame)
MainView.addSubview(VUBarCover)
VUBarCover.backgroundColor = UIColor.blueColor() // use black eventually. blue lets us see it for testing
}
// partially cover up VUBarImage with black VUBarCover coming from the "right"
func updateVUMeter(inputValue:Float) { //inputValue is in dB
//let val = pow(10.0,inputValue/10) // convert from dB
let val = Float( Double(arc4random())/Double(UInt32.max) ) //for Simulator testing, just use random numbers between 0 and 1
print("val = ",val)
let fullWidth = VUBarImageView.frame.width
let maxX = VUBarImageView.frame.maxX
let width = fullWidth * CGFloat(1.0-val)
let minX = maxX - width
let minY = VUBarImageView.frame.minY
let height = VUBarImageView.frame.height
let newFrame = CGRectMake(minX,minY, width, height)
VUBarCover.frame = newFrame
VUBarCover.setNeedsDisplay()
print("fullWidth = ",fullWidth,"width = ",width)
print(" newFrame = ",newFrame,"VUBarCover.frame = ",VUBarCover.frame)
}
样本结果为:
val = 0.9177
fullWidth = 285.0 width = 23.4556210041046
newFrame = (278.544378995895, 93.5, 23.4556210041046, 10.0) VUBarCover.frame = (278.544378995895, 93.5, 23.4556210041046, 10.0)
val = 0.878985
fullWidth = 285.0 width = 34.4891595840454
newFrame = (267.510840415955, 93.5, 34.4891595840454, 10.0) VUBarCover.frame = (267.510840415955, 93.5, 34.4891595840454, 10.0)
val = 0.955011
fullWidth = 285.0 width = 12.8218790888786
newFrame = (289.178120911121, 93.5, 12.8218790888786, 10.0) VUBarCover.frame = (289.178120911121, 93.5, 12.8218790888786, 10.0)
...也就是说,我们看到 VUBarCover.frame 正在改变 'internally',但在屏幕上它永远不会改变。我们看到的是全尺寸封面,完全覆盖了下面的图像(大约 300 像素宽),尽管它的宽度应该只有大约 12 像素)。
即使我在 VUBarCover 的超级视图上执行 setNeedsDisplay(),也没有任何变化。
帮忙?谢谢。
首先,你有几个错误值得注意:
- 实例变量(如
VUBarCover
和MainView
应始终以小写字母开头(如mainView
)。 - 您应该在覆盖实施开始时调用
super.viewDidLayoutSubviews()
其次,viewDidLayoutSubviews()
可以被调用任意次数,所以你对这个方法的实现应该是idempotent,意思是无论调用多少次,效果都是一样的次它被称为。但是当你打电话时:
VUBarCover = UIView(frame: frame)
MainView.addSubview(VUBarCover)
您正在创建一个 new UIView
并将其添加到视图层次结构中,以及您过去可能添加的其他视图。所以它看起来 框架没有在屏幕上更新。事实上,您无法分辨,因为 旧 视图落后于您正在更新的视图,并且它们 没有改变。
相反,您可能想创建一次:
var vuBarCover = UIView()
将其添加为 viewDidLoad()
中的子视图:
mainView.addSubview(vuBarCover)
并在viewDidLayoutSubviews()
中修改其框架:
vuBarCover.frame = vuBarImageView.frame
您不需要致电 setNeedsDisplay()
。
我现在正在制作一个像你一样的自定义 UIView,也许我能帮上忙。
首先,viewDidLayoutSubviews()喜欢你的评论:这会在 AutoLayout 完成后调用。在每个布局都设置好之后,你开始为你的 UIView 和 UIImage 设置新的框架,也许错误就在这里。请尝试将 viewDidLayoutSubviews() 中的代码移动到 layoutSubviews()。并且不要忘记在覆盖函数中添加 super.layoutSubviews() ,这可以帮助您远离数百个错误:].
其次,仅当您覆盖 drawRect: 方法时,您才应该调用 setNeedsDisplay(),它告诉系统我需要重新绘制我的视图,系统将适当地调用 drawRect: 方法。
希望你能想通。
在我的例子中,层上留下了动画,删除它们后,帧更改会更新:
myView.layer.removeAllAnimations()
iOS 在屏幕上显示 UIView
的 presentationLayer
,动画在该层上播放(frame
更新在动画期间进行)。