layoutIfNeeded not working in iPad - ios

layoutIfNeeded is not working properly in iPad but it is working on iPhone. I want to a circular button. On the iPhone the circle is generated properly but in iPad it looks like a rhombus shape.
_btnthur.layer.cornerRadius = _btnthur.frame.size.width/2;
[self._btnthur layoutIfNeeded];
Expected Result :
Current Output:

I can see two main issues here:
In your code here you are setting the cornerRadius on btnthur, but telling btnSat to layout.
You should not be calling layoutIfNeeded, you should be calling setNeedsLayout and allow the run cycle to coalesce layout calls for performance.
Hope this helps :)
Edit for updated question:
Your corner radius is wrong in the second one, it is much too large. Can you check that the frame is correctly set on the button at the point you are setting the corner radius?
You may want to move your code
_btnthur.layer.cornerRadius = _btnthur.frame.size.width/2;
[self._btnthur setNeedsLayout];
into layoutSubviews or viewDidLayoutSubviews (depending on view or view controller) and make sure that the corner radius is always updated when the frame (or more importantly, the size) is set.

Related

UIView corner radius is sharp on small screens

I have a button I'm setting its corner radius like this in ViewDidLoad():
self.myBtn.layer.cornerRadius = self.myBtn.frame.size.height / 2
self.myBtn.layer.masksToBounds = true
The result is great on the iPhone X. Screenshot:
But for some reason in devices that has smaller screens (like iPhone SE) the corners are really sharp and the result isn't what I want to achieve. Screenshot:
Does anybody know why is it happening?
Thanks!
Try to call your code in viewDidAppear (or better in viewDidLayoutSubviews)
It looks like you're using Autolayout. And it seems your button's layout depends on view's layout.
The problem is: the size of viewController's view may be incorrect when viewDidLoad called (but it's corrected before viewDidAppear called).

Autolayout: UIView frame wrong after rotation

I have created my own implementation of a UITabBar (just a UIView instance).
This UIView contains 3 TabBarItem instances. A TabBarItem is a UIView subclass, and each contains the following UI controls:
UIImageView
UILabel
TabBarBadge (custom UIView subclass)
I am laying out the view hierarchy in a storyboard using auto layout.
The badge for a tab bar item should be positioned so that the y-center of the badge is aligned with the top edge of the image view, and it should be aligned to the right side of the image view, with a 4 point overlap (so, left edge of badge aligned with right edge of image view, with a constant of -4).
This works fine when the app loads, whether in portrait or landscape mode. In either case, though, rotating the device ends up with the frame of the badge in the wrong place after rotation finishes.
Here's a printout from the console of the NSLayoutConstraint in question:
<NSLayoutConstraint H:[UIImageView]-(-4)-[TabBarBadge] (active)>
That's exactly what I would expect it to be.
Here's a printout from the console of the TabBarBadge in question (portrait mode; correct presentation):
<TabBarBadge frame = (80.6667 0; 36 20); text = '67'; autoresize = RM+BM>
Here's a printout from the console of the TabBarBadge in question (landscape mode; incorrect presentation):
<TabBarBadge frame = (80.6667 0; 36 20); text = '67'; autoresize = RM+BM>
So, you can see that the frame isn't changing/updating when the rotation occurs.
Here are a couple of screen shots:
Portrait, Correct Display
Landscape, Incorrect Display
Constraints (Printout of constraints above is from this view)
So, what has me confused is that the rest of the TabBarItem is updating correctly. The UIImageView and UILabel are automatically updating correctly. Why is this one frame not updating correctly?
So, first I researched whether a custom drawRect: method might be the cause of my problem. That doesn't appear to be a factor.
Then, I started noticing some odd discrepancies between the view's frame at different times, and how only this particular one (there are actually 3 in the app) was having the problem. The other 2 currently have no values displayed.
Then, I remembered that I use a UIDynamicAnimator when the value is changed to "bounce" the view, in order to bring attention to the new value.
So, the problem is actually that I wasn't "releasing" (in the control sense, not the memory sense) the view from the UIDynamicAnimator when I was done with the animation. (I'm still not sure whether that's a bug or not. It seems to me that if the animation is paused and the constraints should update the view's frame, then perhaps that should occur.)
So, here's the actual code that was "buggy":
- (void)dynamicAnimatorDidPause:(UIDynamicAnimator *)animator {
// {Other code}
}
And here's the code that fixed my issue:
- (void)dynamicAnimatorDidPause:(UIDynamicAnimator *)animator {
// {Other code}
// Code that fixed the issue:
[self.animator removeAllBehaviors];
}
If I need to animate the view again, I just re-create the animator anyway, so this seems to be the best fix.
This appears to be in agreement with Matt's answer here. (I didn't know this was an issue with UIDynamicAnimator when I asked the question.)

UIScrollView includes extra space at bottom

I have a UIScrollView which continually adds extra space at the bottom of its scroll area on iOS 7. If I rotate the device, the problem fixes itself, however, before rotating after first navigating to the view controller, the extra space always appears. I've included an image below:
What I've tried:
Set automaticallyAdjustScrollViewInsets to NO
Checked contentSize, contentOffset and contentInset. All appear fine.
I'm not sure what else to try to solve this issue, and would greatly appreciate any help or direction here!
Edit: As another layer of complexity to this issue... I call a method, updateScrollViewContentSize in my viewDidAppear: method. When I rotate, and it somehow fixes itself, this same method is called. So my contentSize is being set when my view appears and when I rotate.
To make things worse, the content size is always set to 638... Whether there is extra space or not. But, for some reason, the scrollView ignores this until we rotate.
Here is the method to update the contentSize:
- (void)updateScrollViewContentSize {
[self.scrollView setContentSize:CGSizeMake(self.scrollView.frame.size.width, (self.feedbackFooterView.frame.origin.y + self.feedbackFooterView.frame.size.height + 20))];
}

Swift: What is the meaning of viewDidLayoutSubviews?

I have code under viewDidLayoutSubviews with intention of making an image transparent (alpha = 0) in the beginning which slowly fades in (into alpha = 1) with code under viewDidAppear. Also, I have a button which changes it's own label text when pressed.
However, when the button is pressed and the label changes, the image (which I've specified under viewDidLayoutSubviews) also disappears. Which I think is because the code under viewDidLayoutSubviews has been called?
My question is:
1) What is the meaning of viewDidLayoutSubviews? Why is it called when the button label changes? Just briefly/generally, what is setNeedsLayout & setNeedsDisplayInRect?
2) Is it better to use viewWillAppear then?
Here are 2 similar questions but I couldn't understand enough from them:
1) viewDidLayoutSubviews is called when label changes (xcode) (swift)
2) Why viewdidlayoutsubviews call multiple times?
As name suggests, viewDidLayoutSubviews is called when the view of your viewController has just finished its laying out and you can assume that at that point your views are in their correct places/frames according to your autolayout constraints. You shouldn't perform any action assuming your views have their final frames before that method is called: for example, if you try to aView setFrame: in your viewDidLoad it will probably fail/have no effect as autolayout changes its frame during laying out phase. Therefore, if you really need to change its frame, you should call setFrame: in/after viewDidLayoutSubviews
In short, if your concern is about alpha value of an image or imageView, viewDidLayoutSubviews is probably not the correct place. viewDidAppear seems to be more appropriate for this. viewDidAppear is pretty straighforward: when the view appears on the screen, it is called.
Have you tried to read the docs? viewDidLayoutSubviews, setNeedsLayout etc?
Button label change -> width change -> rearrange -> viewDidLayoutSubviews.
You should not treat viewDidLayoutSubviews as a single call event. You should start an image transparency animation in viewDidAppear with UIView.animateWithDuration, it is a good place to start it, since everything is aligned properly. Let the image alpha be 0 in IB or init method and then just animate it.

iOS - viewDidLayoutSubviews called before auto-layout completed on iOS7

We're currently having a problem that only seems to affect iOS7 devices.
Within our .xib file we have two views within a container view (i.e.: not at the top level of the view hierarchy) that need to be circular on display. The views have constraints applied to their position and horizontal spacing within the container, and an aspect ratio condition requiring they are square. The views should expand in width/height on larger screen sizes, respecting the constraints described.
In our VC, we have the following in viewDidLayoutSubviews to force these views to appear circular:
- (void)viewDidLayoutSubviews {
self.progressContentContainerView.layer.cornerRadius = self.progressContentContainerView.frame.size.width/2;
}
This seems to work fine on iOS8, however on iOS7 there is a period after the view has been displayed where the constraints have not yet been applied and the size of the view/views is incorrect (see attached screenshots). This resolves itself and correctly renders a circle after half a second. This only appears to happen when the views that we intend to be circular are NOT at the top level of the VC's view hierarchy which seems to imply that viewDidLayoutSubviews is called before the subviews of subviews have also been laid out.
My guess is that we could potentially fix this issue by subclassing UIView for the nested container, adding references to the circular view within this subclass and overriding viewDidLayoutSubviews here to make the cornerRadius adjustment. This seems like a bit of a workaround though and I'm interested to see if there are other options.
Is there a cleaner/more idiomatic solution to this problem?
I know this is an old question but have you tried calling either:
[self.progressContentContainerView setNeedsUpdateConstraints];
or:
[self.progressContentContainerView layoutIfNeeded];

Resources