UGUI动态生成列表功能实现(增删保存)

在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的尺寸调整成你要的尺寸就可以了。

Unity中使用UGUI动态创建按钮列表非常简单,以下是一个基本的步骤: 1.创建一个空的GameObject作为容器,用于存储所有的按钮。 2.编写脚本来创建按钮。你可以使用Unity的UI.Button组件或自定义按钮。 3.在脚本中,使用循环来创建多个按钮,并将它们添加到容器中。 4.为每个按钮设置位置、大小、文本和其他属性。 5.为每个按钮添加事件处理程序,以便在单击按钮时执行相应的操作。 以下是一个示例脚本,它将创建一个包含5个按钮的列表: ``` using UnityEngine; using UnityEngine.UI; public class ButtonList : MonoBehaviour { public GameObject buttonPrefab; //按钮预制件 public int numberOfButtons; //按钮数量 private void Start() { for (int i = 0; i < numberOfButtons; i++) { GameObject button = Instantiate(buttonPrefab) as GameObject; //创建按钮 button.transform.SetParent(transform, false); //将按钮添加到容器中 button.GetComponentInChildren<Text>().text = "Button " + (i + 1); //设置按钮文本 button.GetComponent<Button>().onClick.AddListener(() => { Debug.Log("Button " + (i + 1) + " clicked"); }); //添加事件处理程序 } } } ``` 这个脚本假定你有一个名为buttonPrefab的按钮预制件,并且你想要创建5个按钮。在Start()方法中,我们使用for循环创建每个按钮,并将它们添加到容器中。我们还设置了每个按钮的文本,并为它们添加了一个单击事件处理程序,以便在单击按钮时输出一条消息。
评论 6
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值