2

I'm making a simple auto-layout UI that consists of a Panel with a background image and three rows of text.

To start with, I have a Vertical Layout Group component in a top-level "Panel" GameObject, set to Control Child Height. It also has a Content Size Fitter with "Preferred" set for Vertical Fit. The Panel object has a background image, and has a few children that represent rows in the view:

Panel [Vertical Layout Group] [Image] [Content Size Fitter]
  - Text 1
  - Text 2
  - Text 3

This all works well as-is.

My problem arises because I want the panel background to compose of two images - one is a filled background image, and the other is a mostly transparent "frame" image that fits over the background and adds detail just to the edges and corners. Both images are sliced.

Unfortunately Unity does not allow more than one Image component on a single GameObject, so this prevents me from simply adding both images to the Panel. If this worked, it would suffice.

Instead, if I add the image to a new child of the Panel then it gets included as a child in the VLG and the frame appears as the new first row, i.e part of the vertical layout. Not what I'm after:

Panel [VLG] [Image:Background] [Content Size Fitter]
  - Frame [Image:Frame]
  - Text 1
  - Text 2
  - Text 3

I tried moving both Images as two children of the Panel, and then adding a third child as "Layout" with the original children as children of that, with the VLG (removing it from Panel):

Panel [Content Size Fitter]
  - Background [Image: Background]
  - Frame [Image:Frame]
  - Layout [VLG]
    - Text 1
    - Text 2
    - Text 3

Unfortunately this doesn't seem to work either, because the dimensions of the two Images are not driven by the Panel if it doesn't contain a Layout Group of some kind. But obviously adding a VLG to Panel would split out Background from Frame and from Layout when I really want all three superimposed.

Is there a way to create a "Composite" Layout Group such that the children are combined on top of each other, rather than horizontally or vertically? I looked at the source code for the UnityEngine.UI.LayoutGroup abstract base class and wondered if I could create something similar to VLG but just puts all the children at the same location by emulating UnityEngine.UI.VerticalLayoutGroup but returning the same Y value for each child position. Would this work?

I know I can manually combine the two images into one and just use a single Image - however I'd like to better understand how I might be able to do this in the general case. Also, you can get more interesting results with run-time composition when the Slice dimensions differ between images.

davidA
  • 12,528
  • 9
  • 64
  • 96
  • Apologies: I also posted this on the GameDevelopment SE because I didn't actually know it existed until shortly after I posted this. However there are a lot of Unity-related questions here and people answering them so I'll leave this up in case someone can help. – davidA Mar 23 '21 at 09:02

2 Answers2

1

try this one

Panel  [Image:Background] [Content Size Fitter]
  - Frame [VLG] [Image:Frame]
    - Text 1
    - Text 2
    - Text 3
Art Zolina III
  • 497
  • 4
  • 10
  • Thank you for the suggestion. That does something, but for some reason the dimensions of the sliced Frame image (which is 900x900 even though it's Sliced) obscure the content dimensions (Text 1,2,3) preventing the Panel from being sized correctly. I think I need to find a way to make Frame's VLG ignore the image attached to itself. Same thing happens with Dialogue - even though the Background image is Sliced, it imposes its preferred size onto the Content Size Fitter. I'll try a few Layout Elements to see if I can avoid that. – davidA Mar 23 '21 at 19:31
  • Yeah, confirmed unfortunately - the dimensions of the sliced image on Dialogue (0x0 because it's sliced with zero margins) block any propagation of the minimum or preferred dimensions that might come up from a child like Frame, so the Background image stays 0x0. Additionally, for reasons I don't understand yet, the dimensions of Frame are not driven by Panel's Content Size Fitter. I tried a VLG on Panel ("Dialogue" in above comment, sorry) to drive the child's (Frame) width and height, but because of the above it ends up 0x0. – davidA Mar 23 '21 at 19:45
  • Ok I'm onto something now - it seems that sometimes just toggling controls in the Inspector produces a different result. I switched the Content Size Fitter from Preferred Size back to Unconstrained **and back again** and it has started to work properly... – davidA Mar 23 '21 at 19:50
  • 1
    @davidA content size fitter will not affect the frame size of its child. its opposite the child size will affect the content size fitter size. think of it as a wrapper of candy its fits arround its child size. try changing the child size and the wrapper will fit itself arround. – Art Zolina III Mar 23 '21 at 23:01
  • Your answer has led to my success - thank you again. The key was to do as you suggested, but also add a VLG to the Panel object, with Child Control Size Width & Height. It seems without that extra VLG the Background image on the Panel was ending up with Preferred Width & Height of zero, making it disappear. Everything else in the stack is working though. – davidA Mar 24 '21 at 08:56
0

With thanks to @Art Zolina III, the key is to put the second image on the only child of the Content Size Fitter, and use a Vertical Layout Group (VLG) on that same child to propagate the final children back to the top-level object (Panel).

Panel [Image:Background, sliced] 
      [Content Size Fitter: Horiz Preferred, Vert Preferred]
      [Vertical Layout Group: Control Child Width, Height]
  - Frame [Image:Framing, sliced] 
          [VLG: Control Child Width, Height; Child Force Expand Width]
    - Text 1 [TextMeshPro Text]
    - Text 2 [TextMeshPro Text]
    - Text 3 [TextMeshPro Text]

As a note, the preferred height of a sliced image is the sum of the top and bottom border heights, which means that it cannot easily shrink to less than that height. This tripped me up because my image had a combined vertical border space of 900 pixels which was fooling me into thinking my layout wasn’t shrinking “to fit”. Once I used a sliced image with smaller top & bottom margins, the panel layout appeared to work correctly.

Additionally, the slicing boundaries of a Sprite seem to be affected by the Pixels Per Unit Multiplier, which means you can make the boundaries smaller than they ought to be visually, but increase the multiplier to still have all the margins rendered in entirety (but at a higher resolution).

davidA
  • 12,528
  • 9
  • 64
  • 96