I'm trying to dynamically resize the frame of a UIView. I can update the frame in the code and see that the values have changed, but the actual display never changes, even though I run setNeedsDisplay().
I'm following this post, where I define a new frame via CGRectMake, and then set the UIView's frame to this new frame. i.e., I'm doing this...
let newFrame = CGRectMake(minX,minY, width, height)
VUBarCover.frame = newFrame
If I print out the value of the UIView's frame, I see that it's changing as I like. But the display (in the Simulator) never reflects these changes.
Any idea how to fix this?
Update: In greater detail: I'm trying to programmatically cover up one UIView with another. It's a horizontal "VU Meter", consisting of a base UIImageView showing a color gradient, that gets partially dynamically "covered" up by a UIView with a black background. The UIImageView "VUBarImageView" is defined in StoryBoard and is subject to AutoLayout. The black UIView "VUBarCover" is defined purely programmatically, with no AutoLayout constraints.
Here's the relevant parts of the code for completeness... The trouble I'm having is in 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)
}
And sample results are:
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)
...i.e., we see that VUBarCover.frame is changing 'internally', but on the screen it never changes. What we see instead is the full-size cover, completely covering the image below (ca. 300 pixels wide), even though its width should be only, about 12 pixels).
Even if I do a setNeedsDisplay() on the superview of VUBarCover, nothing changes.
Help? Thanks.
First, you have a few errors worth noting:
VUBarCover
and MainView
should always begin with a lowercase letter (like mainView
).super.viewDidLayoutSubviews()
at the beginning of your override implementationSecond, viewDidLayoutSubviews()
can be called any number of times, so your implementation of this method should be idempotent, meaning it has an identical effect no matter how many times it's called. But when you call:
VUBarCover = UIView(frame: frame)
MainView.addSubview(VUBarCover)
You are creating a new UIView
and adding it to the view hierarchy, along with the others you may have added in the past. So it looks like the frame isn't updating on the screen. In fact, you just can't tell because the old views are behind the one you're updating and they're not changing.
Instead, you probably want to create this once:
var vuBarCover = UIView()
Add it as a subview in viewDidLoad()
:
mainView.addSubview(vuBarCover)
And modify its frame in viewDidLayoutSubviews()
:
vuBarCover.frame = vuBarImageView.frame
You don't need to call setNeedsDisplay()
.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With