Need help with grid layout (horizontal/vertical based on orientation) PAID

I need help figuring out an issue with Unity, where I have two boxes of data, and I need them to column/row appropriately with orientation change (portrait vs landscape). I am willing to pay someone for their time helping me as long as I can get it solved. Let me know what you’d charge, and if it’s reasonable, I will pay you.

4406911--401128--Unity-Canvas.jpg

I sometimes like looking at these kinds of issues so decided to dabble with this one in particular a bit.

Bad news first:
As far as I’m aware, there so no unity built-in component/script that allows you to decide whether to horizontally or vertically align BASED ON the size of your screen. You only have the horizontal & vertical components that can easily outline either. The grid layout comes the closest, with being able to flexibly determine how many “rows” and “columns” you have, but that means each sub view you have would have a predetermined & constant size, which probably isn’t what you want.

Good news:
Making the view you showed is easy to make in both vertical & horizontal layout, and MOST LIKELY it is very easy to programmatically place a horizontal / vertical layout group on the parent object whenever your screen size and/or orientation changes.

I’ve made a unity project showing both versions separately that you can check out here (it used 2017.4 but it only contains a scene file so probably works with most recent unity versions):

Note that the only difference between the horizontal & vertical view in the project I sent is literally the topmost layout group components, so if you make a script dynamically adding & removing those it should work as a single one instead.

Let me know what you think, perhaps I can help nudge you in the right direction. I have no interest in being paid for this, as the amount of effort spent was negligible

So, I can place a horizontal/vertical group via script, but the issue comes down to tweaking. With that code, it only works when not in the editor, and it only responds to orientation changes (so you can’t just switch the aspect ratio in the edtior). So basically, you have to kind of blindly configure things, build and run, and then see and tweak. And usually, when you tweak one setting for the other orientation, it almost always completely breaks the other one.

Oh – I also forgot to mention: The panel in my example is very basic, but the actual panels are VERY complex in nature, and having multiple copies that I’d have to ‘switch’ to would essentially break nearly a hundred bindings, and I’d have to account for that. Which is why I’m in such a pickle. I was hoping to essentially destroy and instantiate a vertical/horiz layout group with appropriate settings on resolution change. If that makes sense.

How about something like the code below? Add it to one to either "Horizontal’ or “Vertical” in the sample I made and configure the settings. This will work in the editor, so you don’t have to run the game and it simply checks the game (window) resolution.

using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;

[ExecuteInEditMode]
public class DynamicLayout : MonoBehaviour
{
    [SerializeField] private LayoutGroupData horizontalLayoutData = null;
    [SerializeField] private LayoutGroupData verticalLayoutData = null;

    [SerializeField] private float aspectTreshold = 1f;

    private Vector2 currentResolution;

    private HorizontalLayoutGroup existingHorizontalLayout;
    private VerticalLayoutGroup existingVerticalLayout;

    private void Awake()
    {
        // Either will exist, whichever is your default
        existingHorizontalLayout = GetComponent<HorizontalLayoutGroup>();
        existingVerticalLayout = GetComponent<VerticalLayoutGroup>();
    }
    private void OnValidate()
    {
        // Either will exist, whichever is your default
        existingHorizontalLayout = GetComponent<HorizontalLayoutGroup>();
        existingVerticalLayout = GetComponent<VerticalLayoutGroup>();
    }
    private void Reset()
    {
        // Either will exist, whichever is your default
        existingHorizontalLayout = GetComponent<HorizontalLayoutGroup>();
        existingVerticalLayout = GetComponent<VerticalLayoutGroup>();
    }

    private void Update()
    {
        // Check if resolution has changed
        Vector2 newResolution = new Vector2(Screen.width, Screen.height);
        if (currentResolution.x != newResolution.x || currentResolution.y != newResolution.y)
            OnResolutionChanged(newResolution);
    }

    private void OnResolutionChanged(Vector2 newResolution)
    {
        currentResolution = newResolution;

        // Check based on aspect ratio if we need to generate the OTHER layout group
        float aspect = newResolution.x / newResolution.y;
        if (aspect > aspectTreshold)
        {
            if (existingVerticalLayout != null)
                DestroyImmediate(existingVerticalLayout);

            if (existingHorizontalLayout == null)
                AddHorizontalLayoutGroup();
        }
        else
        {
            if (existingHorizontalLayout != null)
                DestroyImmediate(existingHorizontalLayout);

            if (existingVerticalLayout == null)
                AddVerticalLayoutGroup();
        }

        LayoutRebuilder.ForceRebuildLayoutImmediate(transform as RectTransform);
    }

    private void AddHorizontalLayoutGroup()
    {
        HorizontalLayoutGroup layoutGroup = gameObject.AddComponent<HorizontalLayoutGroup>();
        layoutGroup.padding = horizontalLayoutData.padding;
        layoutGroup.spacing = horizontalLayoutData.spacing;

        layoutGroup.childAlignment = horizontalLayoutData.childAlignment;

        layoutGroup.childControlWidth = horizontalLayoutData.childControlWidth;
        layoutGroup.childControlHeight = horizontalLayoutData.childControlHeight;

        layoutGroup.childForceExpandWidth = horizontalLayoutData.childForceExpandWidth;
        layoutGroup.childForceExpandHeight = horizontalLayoutData.childForceExpandHeight;

        existingHorizontalLayout = layoutGroup;
    }
    private void AddVerticalLayoutGroup()
    {
        VerticalLayoutGroup layoutGroup = gameObject.AddComponent<VerticalLayoutGroup>();
        layoutGroup.padding = horizontalLayoutData.padding;
        layoutGroup.spacing = horizontalLayoutData.spacing;

        layoutGroup.childAlignment = horizontalLayoutData.childAlignment;

        layoutGroup.childControlWidth = horizontalLayoutData.childControlWidth;
        layoutGroup.childControlHeight = horizontalLayoutData.childControlHeight;

        layoutGroup.childForceExpandWidth = horizontalLayoutData.childForceExpandWidth;
        layoutGroup.childForceExpandHeight = horizontalLayoutData.childForceExpandHeight;

        existingVerticalLayout = layoutGroup;
    }
}

[Serializable]
public class LayoutGroupData
{
    public RectOffset padding;
    public float spacing;

    public TextAnchor childAlignment;

    public bool childControlWidth;
    public bool childControlHeight;

    public bool childForceExpandWidth;
    public bool childForceExpandHeight;
}

Would this be able to essentially create/destroy on-the-fly? Meaning I don’t need two copies of each layout? I suppose I’d just have one that defaults, and if the screen changes, it destroys the redundant one and instantiates the new one, right?

I’d love to be able to chat about my specific problems and would love a bit more of your time to suss this out. If that’s possible, I’d love to either skype/chat/email/phone to figure out my problem. Just let me know what I can do to make it happen, and I’ll certainly do my best. :smile:

Essentially, I have a client that needs this done, and I’m afraid I’m at the threshold of my Unity experience. I’m a bit over a barrel here. I’d love to tick this box and move on. hahaha

Hey @joelstartech , I suggest you first download the project and copy+paste the script to try this out, I’m quite sure it’s exactly what you’re looking for.

I did. In my project. They’re not expanding to 100% width height based on orientation.

I.e. It tiles in the upper left, and doesn’t scale to fill the window.

I’m assuming it’s something on the child canvases. I just don’t know what to set the anchor points or rects to.

It’s nearly there though.

I’m nearly there, but the panels are now not scaling, and when I put the canvas scaler on, it throws EVERYTHING way off. Any pointers?

In a nutshell: The layout is working, but it’s either taking control over the sub canvases, or some setting I have is throwing things off when it tries to scale.

Any thoughts?

Good to hear you’re getting close! I just sent you a message through conversations

I’m 99% there now. I figured out most of the issues with the layout, but another set of eyes wouldn’t hurt. I’ll message you back. :smile:

Thanks again!