Visual changes to UIView don't immediately take effect

smirk

macrumors 6502a
Original poster
Jul 18, 2002
657
46
Orange County, CA
Hi, I have a UIView onscreen that was created in a storyboard. At some point in the code (after viewDidLoad), the view's layer.cornerRadius is changed to give it rounded corners. However, the view keeps its square corners until the user taps a button and the contents of the screen are slightly changed. At this point, the view is redrawn with rounded corners.

What needs to be done to have the UI update itself immediately? myView.setNeedsDisplay had no effect. I know I could put this in viewDidLoad, but I'm trying to understand why things aren't updating as expected.

Thanks!

Code:
myView.layer.cornerRadius = myView.bounds.height / 2.0
myView.setNeedsDisplay()
 

smirk

macrumors 6502a
Original poster
Jul 18, 2002
657
46
Orange County, CA
Thank you. I will read up more on CALayer. However, myView.layer.setNeedsDisplay() didn't work.

Any other suggestions?

Edit: I figured out the problem! The view serves as a colored background to a label. Even though the label has a text value, it appears that it hasn't been rendered yet, and so its superview (`myView`) doesn't yet have a size.

Is there a way, after assigning a text value to a label, to get it to compute its bounds property?

Edit #2: Ok, I figured it out:
Code:
myLabel.text = "Some words" // myLabel's superview is myView
myView.setNeedsLayout()
myView.layoutIfNeeded()
myView.layer.cornerRadius = myView.bounds.height / 2.0
myView.setNeedsLayout() tells it that something has changed in myView's UI, and myView.layoutIfNeeded() forces myView to lay out its view hierarchy synchronously. Once this has been done, myView.bounds.height actually contains real values.
 
Last edited:

Sean7512

macrumors 6502a
Jun 8, 2005
822
16
Hi, I have a UIView onscreen that was created in a storyboard. At some point in the code (after viewDidLoad), the view's layer.cornerRadius is changed to give it rounded corners. However, the view keeps its square corners until the user taps a button and the contents of the screen are slightly changed. At this point, the view is redrawn with rounded corners.

What needs to be done to have the UI update itself immediately? myView.setNeedsDisplay had no effect. I know I could put this in viewDidLoad, but I'm trying to understand why things aren't updating as expected.

Thanks!

Code:
myView.layer.cornerRadius = myView.bounds.height / 2.0
myView.setNeedsDisplay()

FWIW, you can set the corner radius in storyboard and that may fix your issue. Also ensure you have proper constraints on your elements so they are sized correctly from the beginning.

You can add the corner radius in Storyboard by using the "User Defined Runtime Attributes", which is in the "Identity Inspector"

Hope this helps!
 

smirk

macrumors 6502a
Original poster
Jul 18, 2002
657
46
Orange County, CA
Thanks @Sean7512. I've used user defined runtime attributes to do exactly that in the past, but it doesn't appear to accept expressions as values. For what I want, it would have to be self.bounds.height / 2, and I couldn't figure out a way to get IB to accept that.
 

Sean7512

macrumors 6502a
Jun 8, 2005
822
16
Thanks @Sean7512. I've used user defined runtime attributes to do exactly that in the past, but it doesn't appear to accept expressions as values. For what I want, it would have to be self.bounds.height / 2, and I couldn't figure out a way to get IB to accept that.
Ah yes, this way won't work with an expression.

Did you ever get it working correctly, btw?
 

Essenar

macrumors 6502a
Oct 24, 2008
552
186
Layout "if needed" is pretty low priority.

I've had my entire view loaded and instantiated for at least 5 seconds before any layout changes would take place, so I would force them to the main thread using async.
I don't know how to do this in swift but in Objective-C it goes something like:
Code:
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
                [get some stuff to use for UI change];
                dispatch_async(dispatch_get_main_queue(), ^{
                    [do stuff using 'some stuff to use for UI change];
                });
            });