[YogaKit] Removal of element messes up layout #606

Closed
opened 2017-07-20 08:56:23 -07:00 by kovpas · 10 comments
kovpas commented 2017-07-20 08:56:23 -07:00 (Migrated from github.com)

Report

Issues and Steps to Reproduce

  1. The initial state of the app:
  • A red view with padding = 20
  • A button that adds a label inside the red view
  1. Once you press the button, a label (violet) is added inside the red view:

  2. Once you press the button again, the label gets removed from the red view:

Expected Behavior

State 3 should look exactly like state 1

Actual Behavior

The layout of the state 3 gets messed up. Looks like yoga thinks that the label is still there, also padding gets added twice to the height of the red view.

Link to Code

Demo project is here

# Report - [x] I have searched [existing issues](https://github.com/facebook/yoga/issues) and this is not a duplicate # Issues and Steps to Reproduce 1. The initial state of the app: - A red view with padding = 20 - A button that adds a label inside the red view <img src="https://user-images.githubusercontent.com/1967999/28426191-bf40479a-6d72-11e7-9b38-cbf78e0795da.png" width="250" /> 2. Once you press the button, a label (violet) is added inside the red view: <img src="https://user-images.githubusercontent.com/1967999/28426206-c9360668-6d72-11e7-93f0-33d2a448dc0b.png" width="250" /> 3. Once you press the button again, the label gets removed from the red view: <img src="https://user-images.githubusercontent.com/1967999/28426237-e668b41a-6d72-11e7-8801-5f82fa8f1acf.png" width="250" /> # Expected Behavior State 3 should look exactly like state 1 # Actual Behavior The layout of the state 3 gets messed up. Looks like yoga thinks that the label is still there, also padding gets added twice to the height of the red view. # Link to Code Demo project is [here](https://github.com/kovpas/YogaTest)
artman commented 2017-07-24 06:28:40 -07:00 (Migrated from github.com)

Facing this issue, too.

Facing this issue, too.
d16r commented 2017-07-26 07:20:08 -07:00 (Migrated from github.com)

@emilsjolander I'm kinda stumped about this one...
This is the correct layout when the Violet button is inserted.

1.{*wm: LAY_EXACTLY, hm: LAY_EXACTLY, aw: 414.000000 ah: 736.000000 initial
2.{*wm: EXACTLY, hm: AT_MOST, aw: 414.000000 ah: 736.000000 measure
2.}*wm: EXACTLY, hm: AT_MOST, d: (414.000000, 90.000000) measure
2.{wm: EXACTLY, hm: EXACTLY, aw: 414.000000 ah: 90.000000 flex
2.}wm: EXACTLY, hm: EXACTLY, d: (414.000000, 90.000000) flex
2.{[skipped] wm: EXACTLY, hm: EXACTLY, aw: 414.000000 ah: 50.000000 => d: (414.000000, 50.000000) flex
2.{wm: LAY_EXACTLY, hm: LAY_EXACTLY, aw: 414.000000 ah: 90.000000 stretch
3.{*wm: EXACTLY, hm: EXACTLY, aw: 374.000000 ah: 50.000000 flex
3.}*wm: EXACTLY, hm: EXACTLY, d: (374.000000, 50.000000) flex
3.{[skipped] wm: LAY_EXACTLY, hm: LAY_EXACTLY, aw: 374.000000 ah: 50.000000 => d: (374.000000, 50.000000) stretch
2.}wm: LAY_EXACTLY, hm: LAY_EXACTLY, d: (414.000000, 90.000000) stretch
2.{[skipped] wm: LAY_EXACTLY, hm: LAY_EXACTLY, aw: 414.000000 ah: 50.000000 => d: (414.000000, 50.000000) stretch

This is the changes when you remove the violet button. Looks like the container isn't being remeasured.

1.}*wm: LAY_EXACTLY, hm: LAY_EXACTLY, d: (414.000000, 736.000000) initial

1.{*wm: LAY_EXACTLY, hm: LAY_EXACTLY, aw: 414.000000 ah: 736.000000 initial 2.{*wm: EXACTLY, hm: AT_MOST, aw: 414.000000 ah: 736.000000 measure 2.}*wm: EXACTLY, hm: AT_MOST, d: (414.000000, 130.000000) measure 2.{[skipped] wm: EXACTLY, hm: EXACTLY, aw: 414.000000 ah: 130.000000 => d: (414.000000, 130.000000) flex 2.{[skipped] wm: EXACTLY, hm: EXACTLY, aw: 414.000000 ah: 50.000000 => d: (414.000000, 50.000000) flex 2.{[skipped] wm: LAY_EXACTLY, hm: LAY_EXACTLY, aw: 414.000000 ah: 130.000000 => d: (414.000000, 130.000000) stretch 2.{[skipped] wm: LAY_EXACTLY, hm: LAY_EXACTLY, aw: 414.000000 ah: 50.000000 => d: (414.000000, 50.000000) stretch 1.}*wm: LAY_EXACTLY, hm: LAY_EXACTLY, d: (414.000000, 736.000000) initial
@emilsjolander I'm kinda stumped about this one... This is the correct layout when the Violet button is inserted. 1.{*wm: LAY_EXACTLY, hm: LAY_EXACTLY, aw: 414.000000 ah: 736.000000 initial 2.{*wm: EXACTLY, hm: AT_MOST, aw: 414.000000 ah: 736.000000 measure 2.}*wm: EXACTLY, hm: AT_MOST, d: (414.000000, 90.000000) measure 2.{wm: EXACTLY, hm: EXACTLY, aw: 414.000000 ah: 90.000000 flex 2.}wm: EXACTLY, hm: EXACTLY, d: (414.000000, 90.000000) flex 2.{[skipped] wm: EXACTLY, hm: EXACTLY, aw: 414.000000 ah: 50.000000 => d: (414.000000, 50.000000) flex 2.{wm: LAY_EXACTLY, hm: LAY_EXACTLY, aw: 414.000000 ah: 90.000000 stretch 3.{*wm: EXACTLY, hm: EXACTLY, aw: 374.000000 ah: 50.000000 flex 3.}*wm: EXACTLY, hm: EXACTLY, d: (374.000000, 50.000000) flex 3.{[skipped] wm: LAY_EXACTLY, hm: LAY_EXACTLY, aw: 374.000000 ah: 50.000000 => d: (374.000000, 50.000000) stretch 2.}wm: LAY_EXACTLY, hm: LAY_EXACTLY, d: (414.000000, 90.000000) stretch 2.{[skipped] wm: LAY_EXACTLY, hm: LAY_EXACTLY, aw: 414.000000 ah: 50.000000 => d: (414.000000, 50.000000) stretch This is the changes when you remove the violet button. Looks like the container isn't being remeasured. 1.}*wm: LAY_EXACTLY, hm: LAY_EXACTLY, d: (414.000000, 736.000000) initial <div layout="width: 414; height: 736; top: 0; left: 0;" style="width: 414px; height: 736px; " > <div layout="width: 414; height: 90; top: 0; left: 0;" style="" > <div layout="width: 374; height: 50; top: 20; left: 20;" style="height: 50px; " has-custom-measure="true"></div> </div> <div layout="width: 414; height: 50; top: 90; left: 0;" style="height: 50px; " has-custom-measure="true"></div> </div> 1.{*wm: LAY_EXACTLY, hm: LAY_EXACTLY, aw: 414.000000 ah: 736.000000 initial 2.{*wm: EXACTLY, hm: AT_MOST, aw: 414.000000 ah: 736.000000 measure 2.}*wm: EXACTLY, hm: AT_MOST, d: (414.000000, 130.000000) measure 2.{[skipped] wm: EXACTLY, hm: EXACTLY, aw: 414.000000 ah: 130.000000 => d: (414.000000, 130.000000) flex 2.{[skipped] wm: EXACTLY, hm: EXACTLY, aw: 414.000000 ah: 50.000000 => d: (414.000000, 50.000000) flex 2.{[skipped] wm: LAY_EXACTLY, hm: LAY_EXACTLY, aw: 414.000000 ah: 130.000000 => d: (414.000000, 130.000000) stretch 2.{[skipped] wm: LAY_EXACTLY, hm: LAY_EXACTLY, aw: 414.000000 ah: 50.000000 => d: (414.000000, 50.000000) stretch 1.}*wm: LAY_EXACTLY, hm: LAY_EXACTLY, d: (414.000000, 736.000000) initial <div layout="width: 414; height: 736; top: 0; left: 0;" style="width: 414px; height: 736px; " > <div layout="width: 414; height: 130; top: 0; left: 0;" style="flex-shrink: 1; " has-custom-measure="true"></div> <div layout="width: 414; height: 50; top: 130; left: 0;" style="height: 50px; " has-custom-measure="true"></div> </div>
emilsjolander commented 2017-07-26 09:11:55 -07:00 (Migrated from github.com)

Perhaps some dirty flag isn't being set correctly? However I would be very surprised if this is a bug in the C code and not the objc bindings as we aren't facing any similar issues on other platforms.

Perhaps some dirty flag isn't being set correctly? However I would be very surprised if this is a bug in the C code and not the objc bindings as we aren't facing any similar issues on other platforms.
woehrl01 commented 2017-07-27 00:14:07 -07:00 (Migrated from github.com)

@kovpas Does the behaviour change if you both call applyLayout(preservingOrigin: false) (see the false)

@kovpas Does the behaviour change if you both call `applyLayout(preservingOrigin: false)` (see the `false`)
tadeuzagallo commented 2017-07-27 05:00:53 -07:00 (Migrated from github.com)

@woehrl01 Changing preserveOrigin: false doesn't modify the behaviour.

@emilsjolander even if I manually mark all the views as dirty it still doesn't change the layout. The curious bit is that this doesn't happen with React Native, which is using the same bindings, right?

@woehrl01 Changing `preserveOrigin: false` doesn't modify the behaviour. @emilsjolander even if I manually mark all the views as dirty it still doesn't change the layout. The curious bit is that this doesn't happen with React Native, which is using the same bindings, right?
lucdion commented 2017-07-27 05:31:56 -07:00 (Migrated from github.com)

This is maybe also related to this issue https://github.com/facebook/yoga/issues/603, which is the reversed problem. Adding an element don't relayout its siblings.

This is maybe also related to this issue https://github.com/facebook/yoga/issues/603, which is the reversed problem. Adding an element don't relayout its siblings.
kovpas commented 2017-07-27 07:12:16 -07:00 (Migrated from github.com)

@woehrl01 no, as @tadeuzagallo said, nothing changes if I do preserveOrigin: false

@lucdion I saw #603... The reason I decided to fill a separate issue is that I don't really think it's related: In the case of #603, the view hierarchy remains the same, only yoga layout hierarchy is changed (by setting isIncludedInLayout to false).

In my case, view hierarchy changes which leads to the messed up layout.

@woehrl01 no, as @tadeuzagallo said, nothing changes if I do `preserveOrigin: false` @lucdion I saw #603... The reason I decided to fill a separate issue is that I don't really think it's related: In the case of #603, the view hierarchy remains the same, only yoga layout hierarchy is changed (by setting `isIncludedInLayout` to `false`). In my case, view hierarchy changes which leads to the messed up layout.
d16r commented 2017-07-27 16:32:40 -07:00 (Migrated from github.com)

So, this seems like a UIKit issue. If you set a breakpoint in YGLayout's YGMeasureView function you can see that when we call sizeThatFits: on a plain UIView with no subviews, it is returning a height of 90.

That height of 90 + 40 padding (top and bottom, 20) explains the height of 130. It's unclear why UIView is returning 90 as a height. But it makes it clear that it isn't a yoga problem.

So, this seems like a UIKit issue. If you set a breakpoint in YGLayout's `YGMeasureView` function you can see that when we call `sizeThatFits:` on a plain UIView with no subviews, it is returning a height of 90. That height of 90 + 40 padding (top and bottom, 20) explains the height of 130. It's unclear why UIView is returning 90 as a height. But it makes it clear that it isn't a yoga problem.
kovpas commented 2017-07-28 02:30:19 -07:00 (Migrated from github.com)

@dshahidehpour according to the documentation, this is intended behavior:

The default implementation of this method returns the existing size of the view.

I think what happens is that when there's the violet label inside the red view, sizeThatFits: gets invoked for this label, and red view's size becomes equal to the label's size. If there are no subviews, UIView's implementation of sizeThatFits: just returns bounds.size.

@dshahidehpour according to [the documentation](https://developer.apple.com/documentation/uikit/uiview/1622625-sizethatfits), this is intended behavior: > The default implementation of this method returns the existing size of the view. I think what happens is that when there's the violet label inside the red view, `sizeThatFits:` gets invoked for this label, and red view's size becomes equal to the label's size. If there are no subviews, `UIView`'s implementation of `sizeThatFits:` just returns `bounds.size`.
artman commented 2018-04-13 17:35:23 -07:00 (Migrated from github.com)

Any progress on getting this merged in?

Any progress on getting this merged in?
Sign in to join this conversation.
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: DaddyFrosty/yoga#606
No description provided.