iosuiviewlayoutsubviewsviewdidlayoutsubviews

UIView/CALayer: Transform triggers layoutSubviews in superview


When changing some of the properties for UIView it triggers layoutSubviews in the superview. I can not find any statements about this in the docs.

These properties triggers layout in superview and self

These properties triggers layout in superview only

These properties triggers layout in self only

These properties does not trigger any layout

I find it very confusing that transform is triggering layout and that position and anchorPoint does not.

Example code: https://github.com/hfossli/LayoutSubviewsInconsistency


I want to know:

I can not find anything about this in the docs nor the header files. The problem is significant when using UIDynamics or similar.


Solution

  • Apple answered me via TSI (I personally think this is rubbish):

    Part 1

    why am I seeing this behavior? is this inconsistency or am I misunderstanding some core concepts?

    A view will be flagged for layout whenever the system feels something has changed that requires the view to re-calculate the frames of its subviews. This may occur more often than you'd expect and exactly when the system chooses to flag a view as requiring layout is an implementation detail.

    why does it cascade upwards the view hierarchy?

    Generally, changing a geometric property of a view (or layer) will trigger a cascade of layout invalidations up the view hierarchy because parent views may have Auto Layout constraints involving the modified child. Note that Auto Layout is active in some form regardless of whether you have explicitly enabled it.

    how can I avoid superview to layoutSubviews every time I'm changing transform?

    There is no way to bypass this behavior. It's part of UIKit's internal bookkeeping that is required to keep the view hierarchy consistent.

    Part 2

    Hi Håvard,

    But if this is true I really can not understand why this does not apply to 'layer.anchorPoint' and 'center'/'layer.position'.

    It may be that we are more conservative in this case. Parent views don't need to care about the position of their children except when Auto Layout gets involved. And if Auto layout were involved, you'd need to modify the constraints directly to produce a lasting adjustment in the position anyway.

    This transform triggers layoutSubviews which again cascades upwards.

    It is my understanding that a change to the transform only invalidates the layout of the view's immediate parent (unless you have setup constraints to the changed view, then it becomes more complicated). Also, layout invalidations are batched so your parent's layout subview's method should only be called once per transaction (frame). Still, I can understand that this may cause performance issues if your layout logic is complicated.

    Any ideas?

    Wrap your cell contents in an intermediate view. When you modify the transform of this intermediate view, only the cell's layout should be invalidated, so your expensive layout method won't be called.

    If that doesn't work, create some mechanism to signal to your expensive layout method when it actually does (or does not) have to do work. This could be a property you set when the only changes you make are to the transforms.