davidA
davidA

Reputation: 13664

Unity UI - How to make a "Composite" Layout Group to combine multiple images in the same location?

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.

Upvotes: 2

Views: 1831

Answers (2)

davidA
davidA

Reputation: 13664

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).

Upvotes: 0

Art Zolina III
Art Zolina III

Reputation: 507

try this one

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

Upvotes: 1

Related Questions