Unity3D new UI System and List Views

Gering picture Gering · Sep 15, 2014 · Viewed 17.1k times · Source

I am trying to build a list view with the new Unity UI (2014). The vertical and scrollable list should contain image buttons, which should retain their aspect ratio based on their assigned image! All button should stretch to width of screen. The buttons shouldn't have a gap to the next one. (pretty much like a UITableView in iOS)

enter image description here

I found that the VerticalLayoutGroup which comes with the new UI would not help me, since it does not work well embedded in a ScrollRect. I think it would need to resize based on the containing items in order to get it working with the ScrollRect.

Another problem is that I couldn't get the buttons to retain their width to height aspect ratio, which I solved by writing a little script (see below).

To actually accomplish the desired list effect, I have created a Canvas with a ScrollRect which then contains a RectTransform for my custom ListLayout script. The children of the RectTransforms are the buttons.

The structure looks like this:

enter image description here

Every item in the list gets a keep aspect script which looks like:

public class KeepAspect : MonoBehaviour {

    public Sprite sprite;
    public float aspect = 1;

    void Start() {
        if (sprite != null) {
            aspect = sprite.bounds.size.x / sprite.bounds.size.y;
        }
    }

    void Update() {
        RectTransform rectTransform = GetComponent<RectTransform>();
        Rect rect = rectTransform.rect;
        rectTransform.sizeDelta = new Vector2(rect.width, rect.width * (1f / aspect));
    }
}

My custom ListLayout script, that calculates its height depending of the containing items:

public class ListLayout : MonoBehaviour {

    public enum Direction { Vertical, Horizontal }

    public Direction direction = Direction.Vertical;
    public float spacing = 0;


    void Start() {
    }

    RectTransform[] GetItems() {
        RectTransform rect = GetComponent<RectTransform>();
        RectTransform[] items = new RectTransform[rect.childCount];
        for (int i = 0; i < rect.childCount; i++) {
            items[i] = rect.GetChild(i).GetComponent<RectTransform>();
        }
        return items;
    }

    void Update() {

        RectTransform rectTransform = GetComponent<RectTransform>();
        RectTransform[] items = GetItems();

        // stick together
        if (direction == Direction.Vertical) {

            float y = 0;

            foreach (RectTransform item in items) {
                Rect rect = item.rect;
                item.anchoredPosition = new Vector2(0, -y);
                item.sizeDelta = new Vector2(rectTransform.rect.width, rect.height);
                y += rect.height + spacing;
            }

            // adjust height
            rectTransform.sizeDelta = new Vector2(rectTransform.sizeDelta.x, y);
        }

        // TODO: horizontal layout
    }
}

I have two questions to this approach:

1) Is there a way of doing a list view without custom (ugly) scrips? There has to be a better way?

2) In the KeepAspect script I would love to access the sprite from the GameObject automatically. The thing is, the Sprite is contained in the Image Script of the new UI System and it seems I can't access this one. MonoDevelop could not reference it? Or am I missing something?

Answer

Valera Kogut picture Valera Kogut · Sep 29, 2014

You should use new Unity UI namespace in order to access new UI classes, methods and properties.

As an example:


using UnityEngine;
using UnityEngine.UI; // New Unity UI system from Unity 4.6 version

namespace TestExample {
    public class TestNewUI : MonoBehaviour 
    {
        public Image image;

        public Slider slider;

        private Sprite _sprite;

        void Start()
        {
            _sprite = image.sprite;
        }
    }
}

http://docs.unity3d.com/460/Documentation/ScriptReference/UI.Image.html

https://www.youtube.com/watch?v=TRLsmuYMs8Q


I think that this will help you ;-)