Creating own ListView
- item class to keep data
- component class to display item, derived from ListViewItem
- ListView class derived from ListViewCustom
namespace UIWidgetsSamples.Tasks {
[System.Serializable]
public class Task { public string Name; public int Progress; } }
using UnityEngine.UI;
using UIWidgets;
namespace UIWidgetsSamples.Tasks { public class TaskComponent : ListViewItem { public Text Name; public Progressbar Progressbar; // IViewData<Task> implementation public void SetData(Task item) { Name.text = item.Name; Progressbar.Value = item.Progress; } } }
using UIWidgets;
namespace UIWidgetsSamples.Tasks {
public class TaskView : ListViewCustom<TaskComponent,Task> { } }
Add ScrollRect component to GameObject. With this ListView will be scrollable.
This and some following steps can be skipped if ScrollView gameobject available in your Unity version.
This restricts ListView items to the shape of the Viewport.
Mask can be replaced with RectMask2D.
Set EasyLayout: Layout Type = Grid; Grid Constraint = Fixed Column Count; Grid Constraint Count = 1.
Set Content Size Fitter: Vertical Fit = Preferred Size.
For Horizontal ListView you should set Grid Constraint = Fixed Row Count and Horizontal Fit = Preferred Size instead.
List will be contain items gameobjects and control layout.
You can use Vertical Layout Group or Horizontal Layout Group instead EasyLayout, but in this case changing ListView direction will be impossible in runtime.
Set Text vertical alignment to middle.
Attach ScrollRect GameObject to ScrollRect field.
Attach List GameObject to Container field.
Attach DefaultItem GameObject to DefaultItem field.
Set TaskView colors:
DefaultColor = 255, 215, 115, 255
DefaultBackgroundColor = 255, 215, 115, 0 (transparent)
HighlightedColor = 0, 0, 0, 255 (black)
HighlightedBackgroundColor = 181, 122, 36, 255
SelectedColor = 0, 0, 0, 255 (black)
SelectedBackgroundColor = 196, 156, 39, 255
Background color changes on selection and mouse over.
For this override GraphicsForeground property in component class. (And you can also override GraphicsBackground property.)
GraphicsForeground and GraphicsBackground should return array of Graphic objects for coloring.
using System.Collections;
using System.Collections.Generic;
using UIWidgets;
using UnityEngine;
public class TaskView : ListViewCustom<TaskComponent,Task> {
public static readonly System.Comparison<Task> ItemComparsion = (x, y) => x.Name.CompareTo(y.Name);
public override void Start()
{
base.Start();
DataSource.Comparison = ItemComparsion;//通过ItemComparsion这个来进行对数据进行排序
}
//改变
protected override void SetData(TaskComponent component, Task item)
{
component.SetData(item);
}
//===根据状态动态改变文本颜色
protected override void HighlightColoring(TaskComponent component)
{
base.HighlightColoring(component);
component.Name.color = HighlightedColor;
}
protected override void SelectColoring(TaskComponent component)
{
base.SelectColoring(component);
component.Name.color = SelectedColor;
}
protected override void DefaultColoring(TaskComponent component)
{
base.DefaultColoring(component);
component.Name.color = DefaultColor;
}
//==========================
}
Let's implement automatic sort for items.
ItemsComparison function compare tasks by name and used to sort items.
using UIWidgets;
namespace UIWidgetsSamples.Tasks {
public class TaskView : ListViewCustom<TaskComponent,Task> { public static readonly System.Comparison<Task> ItemsComparison = (x, y) => x.Name.CompareTo(y.Name); bool isStartedTaskView = false; public override void Start() { if (isStartedTaskView) { return ; } isStartedTaskView = true; base.Start(); DataSource.Comparison = ItemsComparison; } } }
Replace Task Progress field with property and add OnProgressChange event.
So now we can get event when Progress value changed.
using UnityEngine;
using UnityEngine.Serialization;
using UIWidgets;
namespace UIWidgetsSamples.Tasks { [System.Serializable] public class Task { public string Name; [SerializeField] [FormerlySerializedAs("Progress")] int progress; public int Progress { get { return progress; } set { progress = value; if (OnProgressChange!=null) { OnProgressChange(); } } } public event OnChange OnProgressChange; } }
When Progress value changed will be called UpdateProgressbar function.
using UnityEngine.UI;
using UIWidgets;
namespace UIWidgetsSamples.Tasks { public class TaskComponent : ListViewItem, IViewData<Task> { public override Graphic[] GraphicsForeground { get { return new Graphic[] {Name, }; } } public Text Name; public Progressbar Progressbar; Task item; public Task Item { get { return item; } set { if (item!=null) { item.OnProgressChange -= UpdateProgressbar; } item = value; if (item!=null) { Name.text = item.Name; Progressbar.Value = item.Progress; item.OnProgressChange += UpdateProgressbar; } } } public void SetData(Task item) { Item = item; } void UpdateProgressbar() { Progressbar.Animate(item.Progress); } protected override void OnDestroy() { Item = null; } } }
It will add task and task progress will be updated every second on random value in range 1..10.
using UnityEngine;
using System.Collections;
namespace UIWidgetsSamples.Tasks { public class TaskTests : MonoBehaviour { public TaskView Tasks; public void AddTask() { var task = new Task(){Name = "Random Task", Progress = 0}; Tasks.DataSource.Add(task); StartCoroutine(UpdateProgress(task, 1f, Random.Range(1, 10))); } IEnumerator UpdateProgress(Task task, float time, int delta) { while (task.Progress < 100) { yield return new WaitForSeconds(time); task.Progress = Mathf.Min(task.Progress + delta, 100); } } } }
Add AddTask() to OnClick event.