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)
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:
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?
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 ;-)