Swift: Changing UIView frame but display doesn't update

change uiview height programmatically autolayout
set frame in swift 4
layoutsubviews
set frame programmatically swift
layoutifneeded
setneedslayout
swift view update layout
update view swift

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.

Frame vs Bounds in iOS - Suragch, To help me remember frame, I think of a picture frame on a wall. You are dribbling the ball all over the basketball court, but you don't really care where the court itself is. It doesn't know anything about where the view is located in the parent view. Now look what happens if we change the bounds' origin coordinates. Custom UIView in Swift done right. UIView {lazy var addButton: Frames do not change after constaint constant change, a full layout cycle should happen.

In my case, there were animations left on the layer, after removing them, the frame changes are updated:

myView.layer.removeAllAnimations()

iOS displays presentationLayer of a UIView on the screen, animations are played on that layer (frame updates goes there during animation).

sizeToFit(), iOS 2.0+; Mac Catalyst 13.0+; tvOS 9.0+ In some cases, if a view does not have a superview, it may size itself to the screen bounds. If you want to change the default sizing information for your view, override the var contentMode: UIView. Changing the parent’s frame, doesn’t automatically change its children’s frames. We’ll use a feature introduced in iOS 7 called UIView snapshots to fix the animation. This allows you to take a snapshot of a UIView together with its hierarchy and render it into a new UIView.

I am making a custom UIView like you right now, maybe I can help.

Firstly, viewDidLayoutSubviews() like your comment: this gets called after AutoLayout is finished. And after every layout did set, you start to set new frame for your UIView and UIImage, maybe the bug is here. Please try to move your code in viewDidLayoutSubviews() to layoutSubviews(). And don't forget add super.layoutSubviews() in override function, which can help you away from hundreds of bugs :].

Secondly, only if you override the drawRect: method, then you should call setNeedsDisplay(), which is telling system that i need to redraw my view, and system will call drawRect: method appropriately.

Hope you can figure it out.

layoutSubviews(), The default implementation of this method does nothing on iOS 5.1 and You can use your implementation to set the frame rectangles of your subviews directly​. The coordinates of the frame rectangle are always specified in points. Warning. If the transform property is not the identity transform, the value of this property is undefined and therefore should be ignored. Changing the frame rectangle automatically redisplays the view without calling its draw(_:) method.

Programming IOS 9: Dive Deep Into Views, View Controllers, and , sizes, in code, and build an animated image which I then display in a UIButton: var arr However, for a limited range of properties, you can animate a UIView directly: these are its alpha, bounds, center, frame, transform, and (if the view doesn't implement drawRect:) You can also animate a UIView's change of contents. Coordinate system. To understand how a frame represents a rectangle on the screen we have to take a look at the coordinate system used by views. The red square has the origin in (x: 200, y: 200) and the size (width: 200, height: 200). The top left corner of the screen is the point is (0, 0) or CGPointZero.

Basic UIView Animation Tutorial: Getting Started, Update note: Ehab Amer updated this tutorial for Xcode 10 and iOS 12. But maybe the best part about UIView animation is that it's incredibly easy to implement. you wanted to animate a view moving across the screen on your own: constraint values, UIView animation doesn't update the view's frame. videogravity avplayerlayer swift (8) I have a UIView which contains an AVPlayer to show a video. When changing orientation, I need to change the size and location of the video. I'm not very experienced with resizing layers, so I'm having problems making the video resize.

Custom UIView in Swift done right - Noteworthy, The internet has many solutions how to define your custom view, but many of let headerView = UIView(frame: CGRect(x: 0, y: 0, width: 300, height: 40)) You should only override this method when changing constraints in  So let’s all vow to be good Swift citizens and start using the Swift versions: let rect = CGRect(x: 0, y: 0, width: 100, height: 100) let size = CGSize(width: 100, height: 100) let point

Comments
  • Aaron, thanks for your detailed answer. Ignoring my stylistic choice of beginning capitals for global variables, I've implemented what you described and the difference is that now, the VUBarCover appears on the display as having zero width, i.e. it doesn't cover the image at all, and otherwise the same issues apply: 'internally' I can see the frame changing via print statements, but on the display nothing happens.
  • Perhaps it's getting cropped by another view? Have you tried using the new-ish Debug View Hierarchy feature? The only other thing I can think of is that maybe you're calling updateVUMeter from a background thread instead of the main thread
  • Background thread was my assumption. @sh37211, what code is calling updateVUMeter?