Search code examples
unity-game-engineunity-ui

Unity - Place UI elements to same y positions with different resolutions


I am working on 1920x1080 reference resolution. Am dynamically creating an UI element more than one. They are animating when they created. These UI elements instantiates from same prefab named "Drift_Stat_Tab". All of these created and animating UI elements using the same Animation motion.

Prefab looks like :

enter image description here

At the end of every animation, am getting the last Keyframe value from the played animation motion (that is "m_AnchoredPosition.y" property) and setting the local position of this UI element :

Stat_Sub_Tab.GetComponent<RectTransform>().localPosition = new Vector3(x_keys[3].value - 960, y_keys[3].value,0f);

When all UI elements created and their animations are finished looks like that at 1920x1080 (reference resolution) :

enter image description here

So far, so good. But when i use different resolution sizes, complications accurs. When try that on 2778x1284 there it goes :

enter image description here

I should be able to scale x and y axis differently. In the same time should set RectTransform.localPosition values differently too. For that i tried this approach :

        int reference_x = 1920;
        int reference_y = 1080;
        int current_x = (int)gameObject.GetComponent<Canvas>().renderingDisplaySize.x;
        int current_y = (int)gameObject.GetComponent<Canvas>().renderingDisplaySize.y;

        // Y Position Calculate REGION

        float const_y_scaler = 1;
        float new_y_scale = 1;
        float y_pos_gap = 13;
        if (current_y > reference_y)
        {
            const_y_scaler = ((float)current_y - reference_y) / reference_y;
            new_y_scale = 1 + const_y_scaler;
            y_pos_gap *= new_y_scale;
        }
        else if (current_y < reference_y)
        {
            const_y_scaler = ((float)reference_y-current_y) / reference_y;
            new_y_scale = 1 - const_y_scaler;
            y_pos_gap *= new_y_scale;
        }
        
        
        float y_pos= ((float)current_y/ 2)-100*new_y_scale -y_pos_gap;
        float reduce_value = (200 * new_y_scale) * instantiate_order_Count;
        y_pos -= reduce_value;
        if (instantiate_order_Count > 0)
        {
            y_pos -= y_pos_gap* instantiate_order_Count;
        }

        Stat_Sub_Tab.GetComponent<RectTransform>().localScale = new Vector3(new_x_scale, new_y_scale, 1f);

In the code above getting a multiplier for scale the y, and changing the scale of it. In the same time using same multiplier for calculate the y position dynamically. At the end of function setting that "y_pos" value to RectTransform.localPosition.y as "y_keys3.value".

For some different resolutions that approach works fine but some of them like 2778x1284(should be iPhone 11 Pro or mini) not works. Am just drowned a little bit in the code. If is there any advice like using RectTransformUtility or methods like Camera.ViewportToScreenPoint, i would be glad. Thanks in advance


Solution

  • By default, Unity's canvas system uses pixel coordinates. There's two (basic) solutions to supporting multiple different resolutions: using anchors, or a Canvas Scaler set to "Scale By Screen Size"


    Anchors

    Anchors are percentage-based coordinates (0.0-1.0), rather than absolute coordinates (0-1920px). Rather than saying "This UI element should be 100 pixels wide", you can rather use these percentage based coordinates: "This UI element should be take up half the screen, regardless of pixel size, on the X axis." (0-0.5)

    You can set anchors within the RectTransform of the UI element, under the "anchors" tab.

    Canvas Scaler

    A Canvas Scaler lets you continue using these absolute pixel offsets, and will automatically scale the UI to match the screen's size. This does have the downside of having a fixed aspect ratio, requiring the canvas to either be shrunk/expand to fit. (Ex: 16:9 -> 4:3 will make the UI elements either shrink or stretch, depending on the width/height slider in the Canvas Scaler)

    This is the easiest "drop-in" fix, though making the change to anchors might be worth it if you ever want to properly support arbitrary aspect ratios.


    Also, a Vertical Layout Group seems like it would be useful here, it'll automatically lay out your elements in a vertical list so you don't have to position them manually in code. Add a layout group to a parent element, and the elements will arrange themselves according to the parent's size/scale/position.