UGUI的列表
Unity3D提供的UGUI系统非常适合于制作基本的用户图形操作界面,也就是常说的GUI。在标准的UGUI组件包里有很多常用的UI组件,只需要将它们进行组合便能制作出合乎要求又好用的图形界面。
但是UGUI并没有提供一个常用的界面组件,即列表展示组件,取而代之的是一个更加泛化的滑动组件ScrollView,这个组件的特点就是能轻松地做出水平或垂直方向有滑动能力的界面组件,甚至任意方向滑动也不难做到,可以使用它来制作诸如垂直或者水平的列表以及可以随意滑动的地图等。
固然使用ScrollView实现列表展示毫无压力,灵活性也更高,但针对特定的项目需求,使用封装好的列表组件无疑是能大大增加开发效率的。
ScrollView功能窄化 — 封装列表组件
要封装属于自己的列表组件,直接从ScrollView入手是很不错的开始,那么如何利用ScrollView来封装一个列表呢?
首先要看ScrollView的结构,在Unity中新增一个标准ScrollView组件到Canvas上就能看到,ScrollView的结构如下所示
- ScrollView
- Viewport
- Content
- Scrollbar Vertical
- Sliding Area
- Handle
- Sliding Area
- Scrollbar Horizontal
- Sliding Area
- Handle
- Sliding Area
- Viewport
结构中的Viewport/Content便是最主要的放置列表项的地方,两个Scrollbar毫无疑问是滚动条,一个控制水平一个控制垂直,Sliding Area限制了滚动条的区域,Handle则是滚动条中用来表示当前位置的滑块。
那么要制作一个列表,首先就是确定列表是水平的还是垂直的,如果不确定这一点,列表会退化为一个可以随意滑动的区域,失去了设计列表的本意。
一般而言列表是垂直的,那么就按照垂直列表的情况来,如果有水平列表需求,其设计过程也是类似的。
因此先调整ScrollView属性页上的ScrollRect组件
将Horizontal后面的勾去掉,则该ScrollView会被限制只能在垂直方向上滑动,这样一来水平的滚动条也就失去了作用,将它删掉并调整垂直滚动条的大小让它适应整个ScrollView即可。
调整完成后如图所示
现在有了一个仅能垂直滑动的组件,下一步就是将它变成一个列表了。而UGUI并没有原生列表的概念,因此要想实现列表,只能模拟。
所谓模拟列表就是指将列表显示的子项放入Content中让它显示出来,因为Viewport上挂载了Mask组件,所以当Content的内容范围很大,超出了Viewport的大小后就会被裁剪,而ScrollView挂载的ScrollRect组件则保证了其Content子元素可以滑动,这样便模拟出了列表的效果。
从模拟的过程可以看出,其实这个列表是把所有要显示的东西放到界面上,然后用Mask裁剪,展现给用户的就是裁剪过后的样子;再通过ScrollRect滑动起来,就像是滑动出了下面的子项一样。
知道了这个流程,那么方案也随之出炉了,既然模拟这个列表的重点在Content,那么只需要给ScrollView挂上脚本,用脚本控制Content中的子项即可。
列表子项控制脚本
public class ListItem : MonoBehaviour {
private Text contentText;
private string contentStr;
private bool needUpdate = false;
void Start() {
contentText = gameObject.GetComponent<Text>();
}
void Update() {
if(needUpdate) {
contentText.text = contentStr;
needUpdate = false;
}
}
public void setContent(string data) {
contentStr = data;
needUpdate = true;
}
}
以上脚本应挂载到列表的子项预制体上,方便控制每一项的显示
列表控制脚本
public class ScrollList : MonoBehaviour {
public GameObject itemPrefab;
private Transform content;
private List<string> dataList;
private bool needUpdate = false;
void Start() {
content = transform.Find("Viewport/Content");
}
void Update() {
if(needUpdate) {
if(dataList != null) {
for(int i = 0; i < dataList.Count; i++) {
if(i < content.childCount) {
content.getChild(i).gameObject.GetComponent<ListItem>().setData(dataList[i]);
} else {
GameObject obj = GameObject.Instantiate(itemPrefab);
obj.GetComponent<ListItem>().setData(dataList[i]);
}
}
if(dataList.Count < content.childCount) {
for(int i = dataList.Count; i < content.childCount; i++) {
Destory(content.getChild(i).gameObject);
}
}
}
needUpdate = false;
}
}
public void setData(List<string> data) {
dataList = data;
needUpdate = true;
}
}
将以上脚本挂载到之前修改好的ScrollView组件上,列表就可以使用了。
实际使用中只需要获取到列表对象上挂载的ScrollList脚本对象,并使用它来设置好数据列表,组件会自动生成足够的预制体来显示内容,多余的则会被摧毁掉。
但这个组件现在依然是有问题的,最大的一个问题就是它现在还无法正常滑动,而且子项的显示也有问题,运行后回到编辑器界面可以看到,被创建的子项会处于错误的位置导致无法显示,因此还要对组件本身进行一番修改。
首先是为Content对象挂载一个VerticalLayoutGroup组件,然后将其ChildForceExpand属性的两个值Width和Height都勾上。