在UGUI 裡不免會有一些清單需要生成和顯示。例如最簡單的增、删、改、查等都需要清單的變化。本文隻講增、删、儲存、清空UGUI配合的變化方法。
下面以實作場景裡角色的實時位置的增加、删除、儲存為案例開講。
先看一下實作增加效果圖:
首先是UI的制作,這個比較簡單,之前講過的,可以參考:http://blog.csdn.net/alayeshi/article/details/50240075
下面圖檔是整個清單的核心--grid和其子物體,grid就是生成所有子物體的父物體,而這些子物體就是新生成的清單裡的每一行,在grid上規定好子物體的寬度和高度,然後加上Generaterecord腳本。
下面實作增加功能:
點選按鈕增加一個grid的子物體,也就是新增加清單裡的一行。gridlayoutgroup 是會自動排布好你增加出來的子物體。是以我們隻需要寫增加物體的代碼就好。
而增加的方法其實就是在整個代碼裡的生成子物體的方法Generategrids()。在這個方法裡不要忘記每增加一個gird的子物體都要将gird的高度增加,是以有了這句代碼:
this.gameObject.GetComponent<RectTransform>().sizeDelta = new Vector2(this.gameObject.GetComponent<RectTransform>().sizeDelta.x, this.gameObject.GetComponent<RectTransform>().sizeDelta.y + this.GetComponent<GridLayoutGroup>().cellSize.y + this.GetComponent<GridLayoutGroup>().spacing.y);
删除的操作:
因為删除是多選删除,每次删除清單裡的個數不确定,所有我們要給一個标記,是以會看到下圖中會有一個toggle。如果Toggle是被選中的狀态并且點選了删除按鈕那麼清單裡所有被選中的行都會被删除。在代碼裡需要一個list來儲存所有被添加進來的子物體們,在删除時要周遊他們,然後根據toggle的狀态決定這些子物體中那些要被删除,删除要destroy被選中的物體,還要把list裡的對應的移除掉,以及把grid的高度改變。整個方法在代碼裡是Destroyselfs()整個方法。
下面實作儲存的方法:
儲存我們用unity自己的方法 PlayerPrefs.SetInt();原理很簡單,它裡面的兩個參數分别是一個key,一個value。根據key來判斷value。例如: PlayerPrefs.SetInt("存儲個數", gridlist.Count);如果“存儲個數”整個字元串是存在的那麼就可以獲得gridlist.count整個value。是以我們在儲存的時候要保證key是不同的。然後當下次運作時就根據key來判斷,然後加載那些value并且顯示到清單的行中。
具體要看以下代碼:
下面是以上增删儲存的全部的代碼:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
public class generaterecords : MonoBehaviour
{
public Button ADD, Delete, Save, Clearsave;
private string gridpath;
private GameObject gridrecord;
string positions;//用來解析位置資訊
Vector3 personpositions;//坐标位置
List<string> postionlist = new List<string>();//儲存grid裡面的文字
List<string> describepositionlist = new List<string>();//位置前的文字描述
List<GameObject> gridlist = new List<GameObject>(); //用來存儲grid下的對象
GameObject go;//生成的grid子物體
string loadpositions;//加載的位置資訊
string loadstring;//加載位置資訊對應的文字
// Use this for initialization
void Start()
{
ADD.onClick.AddListener(Addposition);
Delete.onClick.AddListener(Deletposition);
Save.onClick.AddListener(Saveposition);
Clearsave.onClick.AddListener(Clearall);
gridpath = "backup/gridcontent";
gridrecord = Resources.Load(gridpath, typeof(GameObject)) as GameObject;
if (gridrecord != null)
{
Debug.Log(gridrecord.name);
}
//清空位置的list
postionlist.Clear();
//清空物體list
gridlist.Clear();
///初始化加載grid物體個數
///
if (PlayerPrefs.GetInt("存儲個數", 0) > 0)
{
Debug.Log("獲得到存儲的個數是" + PlayerPrefs.GetInt("存儲個數", 0));
//周遊存儲的個數,并生産grid物體
for (int i = 0; i < PlayerPrefs.GetInt("存儲個數", 0); i++)
{
Debug.Log("獲得的目前存儲key是" + i);
//擷取儲存的位置資料--以備填充到grids物體裡
///通過key來進行擷取數值,key一定是從0開始的,隻要最後小于存儲個數(也就是list.count)一位就OK,
///而該for循環裡的i也是從0開始的是以正好
if (i < PlayerPrefs.GetInt("存儲個數", 0))
{
loadpositions = PlayerPrefs.GetString(i.ToString(), "沒有該key呀");
Debug.Log("擷取的内容;" + loadpositions);
postionlist.Add(loadpositions);
loadstring = PlayerPrefs.GetString(i.ToString() + "describe", "描述位置的文字");
describepositionlist.Add(loadstring);
}
//生成grids物體
Generategrids();
}
}
else
{
Debug.Log("存儲次數竟然為" + PlayerPrefs.GetInt("存儲次數", 0));
}
}
//添加方法
void Addposition()
{
//主角位置資訊擷取
personpositions = GameObject.Find("FPSControllermine").transform.position;
positions = personpositions.ToString();
Debug.Log("主角位置:" + positions);
Generategrids();
//生成文字位置
Generateposition();
}
//delet方法
void Deletposition()
{
Destroyselfs();
}
儲存的方法
void Saveposition()
{
Debug.Log("描述文字:8888");
if (gridlist.Count > 0)
{
for (int i = 0; i < gridlist.Count; i++)
{
Debug.Log("描述文字:qqq");
//存的描述的文字不能是空和“”
if (gridlist[i].transform.FindChild("InputField/Text").GetComponent<Text>().text != "")
{
Debug.Log("描述文字:ssss");
string describetextfor = gridlist[i].transform.FindChild("InputField/Text").GetComponent<Text>().text;//保持描述
string positionstextfor = gridlist[i].transform.FindChild("positontext").GetComponent<Text>().text;//儲存位置
deleteclicksaved(i, positionstextfor, describetextfor);//儲存方法
Debug.Log("描述文字:" + describetextfor);
}
}
}
}
/// <summary>
/// 清空方法
/// </summary>
void Clearall()
{
PlayerPrefs.DeleteAll();
}
// Update is called once per frame
void Update()
{
}
/// <summary>
/// 生成整個gird子物體
/// </summary>
public void Generategrids()
{
//生成record的物體、
go = Instantiate(gridrecord, this.transform.position, Quaternion.identity);
go.transform.SetParent(this.transform);
//預設是false,也就是不被選中的
go.transform.FindChild("Toggle").GetComponent<Toggle>().isOn = false;
//每一個go位置資訊顯示(加載過來的文本顯示)
if (loadpositions != null)
{
go.transform.FindChild("positontext").GetComponent<Text>().text = loadpositions;//位置的文字
go.transform.FindChild("InputField/content").gameObject.SetActive(true);//顯示出來不可更改的東西 (描述文字的父物體)
go.transform.FindChild("InputField/content/changed").GetComponent<Text>().text = loadstring; //描述文字
}
gridlist.Add(go);
Debug.Log("物體個數" + gridlist.Count);
//本grid長度加go的高度
this.gameObject.GetComponent<RectTransform>().sizeDelta = new Vector2(this.gameObject.GetComponent<RectTransform>().sizeDelta.x, this.gameObject.GetComponent<RectTransform>().sizeDelta.y + this.GetComponent<GridLayoutGroup>().cellSize.y + this.GetComponent<GridLayoutGroup>().spacing.y);
Debug.Log("grid的高度" + this.gameObject.GetComponent<RectTransform>().sizeDelta);
}
/// <summary>
/// 位置擷取,隻有新添加位置才會觸發,從外面加載不走這裡
/// </summary>
///
private void Generateposition()
{
//位置資訊顯示
go.transform.FindChild("positontext").GetComponent<Text>().text = positions;
go.transform.FindChild("InputField/content").gameObject.SetActive(false);//描述文字的父物體不顯示
}
/// <summary>
/// 銷毀被選中的gird子物體
/// </summary>
///
void Destroyselfs()
{
//因為gridlist的數量會在銷毀期間變,是以把即将銷毀的取出來存放然後銷毀
//取出被勾選,将銷毀的物體
// for (int i = 0; i <gridlist.Count; i++)
for (int i = gridlist.Count - 1; i >= 0; i--)
{
Debug.Log("list裡有" + gridlist.Count + "個gird----" + "第" + i + "個是" + gridlist[i].transform.FindChild("Toggle").GetComponent<Toggle>().isOn);
if (gridlist[i].transform.FindChild("Toggle").GetComponent<Toggle>().isOn)
{
//所謂的key就是該物體目前在list裡所處的位置
Destroy(gridlist[i]);
// 将對應裡面的坐标list銷毀
// postionlist.Remove(postionlist[i]);
//将物體引用list銷毀
gridlist.Remove(gridlist[i]);
//本grid長度減少60
this.gameObject.GetComponent<RectTransform>().sizeDelta = new Vector2(this.gameObject.GetComponent<RectTransform>().sizeDelta.x, this.gameObject.GetComponent<RectTransform>().sizeDelta.y - this.GetComponent<GridLayoutGroup>().cellSize.y - this.GetComponent<GridLayoutGroup>().spacing.y);
Debug.Log("删除後list裡有" + gridlist.Count);
//将本次删除完剩下的list周遊,擷取每個物體的key,然後儲存起來
for (int rest = 0; rest < gridlist.Count; rest++)
{
// if (gridlist[i].transform.FindChild("InputField/changed").GetComponent<Text>().text == "")
{
string savetext = gridlist[rest].transform.FindChild("positontext").GetComponent<Text>().text;
string describetext = gridlist[rest].transform.FindChild("InputField/content/changed").GetComponent<Text>().text; //描述文字
deleteclicksaved(rest, savetext, describetext);
}
}
if (gridlist.Count == 0)
{
PlayerPrefs.SetInt("存儲個數", gridlist.Count);
}
}
}
}
void deleteclicksaved(int listkey, string saveposi, string described)
{
PlayerPrefs.SetInt("存儲個數", gridlist.Count);
//存儲個數就是最後剩下的list裡的個數,比key的最大值大一,因為key是從0開始的
Debug.Log("存儲key是" + listkey + "值是" + described);
//儲存每個位置
PlayerPrefs.SetString(listkey.ToString(), saveposi);
//儲存描述文字
PlayerPrefs.SetString(listkey.ToString() + "describe", described);
}
}
注:
在我設計的這個需求裡,儲存過的清單再次加載出來是不允許修改的。
實作這個很簡單,在原來輸入框(Inputfield)上又遮擋了一個透明的圖檔(此圖名曰:content,預設是不出現這個圖檔的因為出現了就無法點選輸入了),目的就是為了當被儲存的輸入框再次加載後滑鼠點選沒有反應,又因為是透明的圖檔是以依然可以看到之前你儲存的名字。
這就是為什麼代碼裡會出現這句代碼: go.transform.FindChild("InputField/content").gameObject.SetActive(false);
如下圖:
這樣所有的功能都實作了。如果你不想看原理,那就是把上面的腳本綁定到grid(你要展示的清單)上再把UI的尺寸調整成你要的尺寸就可以了。