2

Does anyone know why UITextView.layoutSubviews() is not called when rotating a device to portrait mode?

When rotating to landscape mode, these are called:

  • UIViewController.viewWillTransition
  • UIViewController.viewDidLayoutSubviews
  • UITextView.layoutSubviews
  • UILabel.layoutSubviews

But when rotating back to portrait, the UILabel.layoutSubviews() is called, but not the UITextView.layoutSubviews. This is in an empty project with no other code apart from traces in these methods.

Lena Verhoev
  • 231
  • 1
  • 3
  • 15
  • Do you see any layout issues when it not being called in this case? – jesse May 17 '20 at 14:49
  • There are no layout warnings. The reason I need the UITextView.layoutSubviews method to be called is because I intend to have offset code inside UITextView.layoutSubviews() which will vertically-center the text. I've tested with this code in as well, and on rotation from vertical to portrait, it redraws UITextView with the text at vertical-top, without calling layoutSubviews(). I'm really not sure where/how to intercept this. – Lena Verhoev May 18 '20 at 16:27
  • What if in `UIViewController.viewDidLayoutSubviews` you call `textView.setNeedsLayout()`? – jesse May 18 '20 at 16:42
  • That doesn't work either – Lena Verhoev May 18 '20 at 22:24

2 Answers2

1

layoutSubviews is usually called when setNeedsLayout() is invoked already in the previous invocation of run loop.

If the layout system does not think it needs to be called, it will not be called.

Ideally you should not override this function. You should just call setNeedsLayout() after making superview changes, and let the layout system call the default implementation of this function. Morever, you should define your subview layout needs inside auto-layout so it is able to get correct values from there.

If you want immediate update, you should call layoutIfNeeded().

This is because this is one of those methods that are called arbitrarily by UIKit framework and it may not be ideal for your layout needs.

Nirav Bhatt
  • 6,940
  • 5
  • 45
  • 89
1

There are 2 separate things here.

  1. Understanding layoutSubviews(). I.e. when and where to use it.
  2. How to achieve what you want to do the right way. I.e. doing something with the UITextView at device rotation.

About the layoutSubviews(), you should not put any logic here as your view is not having any sub views.

You may say that we expect iOS to call it, so we can put some implementation here, but again, that is not the right way. layoutSubviews() is not meant to alter the view itself, but just laying out sub views.

I would recommend reading more on layoutSubviews(). I learnt from here, when I started learning iOS.

Now to achieve what you want to do, i.e. do something at the time of device rotation, you proper way is to use viewWillTransition(to:with:) method of UIViewController.

In this method, you can put logic to do something just before the transition will happen.

And you can also put logic which will execute during the transition OR after the transition completes, using the UIViewControllerTransitionCoordinator parameter passed to viewWillTransition(to:with:)

Hope this helps!