cbess/AutoScrollLabel

AutoScrollLabel width not autoresizing in UINavigationBar (titleView)

Closed this issue · 12 comments

I've placed an AutoScrollLabel as a titleView in the Navigation Item of a UIViewController, which is in a UINavigationController stack. The AutoScrollLabel should fill out the entire space between the left and right UIBarButtonItem.
In portrait mode this works well, but as soon as I turn the device in landscape mode, the AutoScrollLabel keeps its width and stays centered instead of getting autoresized and filling out the space between the 2 UIBarButtonItems as before.

I really appreciate any help

Thanks Linard

Err... Does it auto-resize in the view controller's view?

I tried it out with the AutoScrollLabelDemo. Unfortunately I cann't upload the modified project but I edited following:

  • Enlarged the self.autoScrollLabel in IB to 280 width
  • Set the autoresizing mask in IB for self.autoScrollLabel and self.navigationBarScrollLabel (as shown in the attached screenshot)

In order that the 2 labels/views are scrolling after the rotation, I had to add following piece of code to ASLViewController.m:

  • (void)willAnimateRotationToInterfaceOrientation:(__unused UIInterfaceOrientation)toInterfaceOrientation duration:(NSTimeInterval)duration
    {
    [self.autoScrollLabel scrollLabelIfNeeded];
    [self.navigationBarScrollLabel scrollLabelIfNeeded];
    }

If you rotate now the device from portrait to landscape orientation, the 2 views are scrolling, but I noticed that shortly after the rotation the 2 views are scrolling very fast for one time before they start to scroll with the correct speed.
In addition to that I looks like that the end of the scrolling is wrong calculated (the scrolling stops somewhere in the middle of the 2nd UILabel instead of its beginning). I tested that with the iPhone Simulator running iOS 6.1. I used a text string needs to be scrolling in portrait but isn't enough long for scrolling for landscape but it gets scrolled anyway.

Thank you very much for any help

Linard
autoscrolllabelautosizing

Does it auto-resize in the view controller's view?

Both views get auto-resized, but there's an issue with the animation's calculation

A small update:
If I change the code as following, I can get rid of that fast scrolling after the rotation:

  • (void)willAnimateRotationToInterfaceOrientation:(__unused UIInterfaceOrientation)toInterfaceOrientation duration:(NSTimeInterval)duration
    {
    //[self.autoScrollLabel scrollLabelIfNeeded];
    //[self.navigationBarScrollLabel scrollLabelIfNeeded];
    }
  • (void)didRotateFromInterfaceOrientation:(UIInterfaceOrientation)fromInterfaceOrientation
    {
    [self.autoScrollLabel scrollLabelIfNeeded];
    [self.navigationBarScrollLabel scrollLabelIfNeeded];
    }

After stepping through scrollLabelIfNeeded it looks like that self.mainLabel.bounds.size.width has a strange value, but I will check that now more detailed.
Can you please explain what following line does (inside - (void)refreshLabels)?
size.width = CGRectGetWidth(self.mainLabel.bounds) + CGRectGetWidth(self.bounds) + self.labelSpacing;

Thanks

I got it!

Instead of using "scrollLabelIfNeeded" we have to use "refreshLabels"! The reason is that the frames of the scrolling Labels have to be recalculated.

This is the final code (for the AutoScrollLabelDemo):

  • (void)didRotateFromInterfaceOrientation:(UIInterfaceOrientation)fromInterfaceOrientation
    {
    [self.autoScrollLabel refreshLabels];
    [self.navigationBarScrollLabel refreshLabels];
    }

Put it in "didRotateFromInterfaceOrientation:" and not in "willAnimateRotationToInterfaceOrientation: duration:" to avoid that fast scrolling shortly after the rotation!

I hope this will help someone in the future...

Linard

Thanks. I will see if I can update the code to reflect your finds, automate this "fix."

Check out the observer-notifications branch and test it out. It should work as expected.

After trying it out in my own code (autolayout enabled) the titleView in the NavigationBar has still the wrong width. I tested it out without CBAutoScrollLabel (just a plain UIView) and saw the same behavior.
For this reason I opened a thread at stackoverflow.com: http://stackoverflow.com/questions/18235349/autoresize-titleview-in-a-navigationbar-with-autolayout

Any help is really appreciated!

So... did the branch help/address other issues?

I just did a lot of testing with AutoScrollLabel in the NavigationBar and it's so confusing!
Here are my results:
I tested iOS 5, iOS 6 and iOS 6.1 (all 3 in the iPhone Simulator) together with CBScrollLabel and device rotation and (in iOS 6.0 and iOS 6.1) autolayout enabled and disabled.

In order that the titleView fills out the entire width between the BarButtonItems you have to set the right autoresizing masks (as shown in the screenshot above, if autolayout is disabled) and if autolayout is enabled, the titleView doesn't get resized.
Following piece of code will enlarge the titleView and the navigationBar will automatically scale it down so that it fits in between the BarButtonItems (this is just necessary for iOS 6 and above, because iOS 5 doesn't support autolayout at all):

//Update 08/18/2013: I found out, that the entire frame of the titleView has to be set, in order that the titleView and the autoScrollLabel are still centered in the navigationBar, because the height is different in portrait and landscape!

 - (void)willAnimateRotationToInterfaceOrientation:(__unused UIInterfaceOrientation)toInterfaceOrientation duration:(NSTimeInterval)duration
 {
      [super willAnimateRotationToInterfaceOrientation:toInterfaceOrientation duration:duration];

      NSString *reqSysVer = @"6.0";
      NSString *currSysVer = [[UIDevice currentDevice] systemVersion];

      if ([currSysVer compare:reqSysVer options:NSNumericSearch] != NSOrderedAscending)
      {
          //>= iOS 6
          //Update 08/18/2013:
          CGRect navigationBarFrame = self.navigationController.navigationBar.frame;
          self.navigationItem.titleView.frame = navigationBarFrame;
          /*
          CGSize navigationBarSize = self.navigationController.navigationBar.frame.size;
          CBAutoScrollLabel *scrollLabel = (CBAutoScrollLabel *)self.navigationItem.titleView;
          CGRect scrollLabelFrame = scrollLabel.frame;
          scrollLabelFrame.size = navigationBarSize;
          self.navigationItem.titleView.frame = scrollLabelFrame;
          */
      }
  }

If you change the AutoScrollLabel's frame size, you have to call "scrollLabelIfNeeded", because it just won't scroll without it:

  - (void)didRotateFromInterfaceOrientation:(UIInterfaceOrientation)fromInterfaceOrientation
  {
      [super didRotateFromInterfaceOrientation:fromInterfaceOrientation];

      //Update 08/18/2013: in order that the AutoScrollLabel is centered in the navBar we have to call refreshLabels instead of just scrollLabelIfNeeded
      [self.currentValuesNavTitleLabelOutlet refreshLabels];
      /*
      NSString *reqSysVer = @"6.0";
      NSString *currSysVer = [[UIDevice currentDevice] systemVersion];

      if ([currSysVer compare:reqSysVer options:NSNumericSearch] != NSOrderedAscending)
      {
          //>= iOS 6
          [self.navigationBarScrollLabel scrollLabelIfNeeded];
      }
      */
  }

If you don't change the frame size while rotating and autolayout is enabled, you don't have to call neither "scrollLabelIfNeeded" nor "refreshLabels".

If you have iOS 5, iOS 6 or iOS 6.1 with autolayout disabled and the correct autoresizing masks, you need following piece of code to get the device rotation to work correctly:

  - (void)didRotateFromInterfaceOrientation:(UIInterfaceOrientation)fromInterfaceOrientation
  {
      [self.navigationBarScrollLabel refreshLabels];
  }

@cbess: thanks for the observer-notifications code, but after my testing the rotation handling is a bit more complex than just registering for the notifications. And the other point is, that your new method has to be called in "commonInit"!

I hope I could help

Linard

Thanks for this insight. It helped me with a similar issue I was having.