简体   繁体   中英

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.)

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM