Unity实用小工具或脚本—利用反射制作动态编辑栏(一)

本文介绍了一种使用C#反射技术动态创建UI编辑器的方法,能够根据结构体或类的字段自动匹配并创建编辑框,简化了UI制作流程,提高了效率。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

一、前言
       在制作UI的时候,经常会碰到对不同的结构体或者类进行编辑,然后要根结构体或类的字段或属性制作对应的输入框。比如int型的输入框内就不能输入字符,就要限定输入框的类型;每个输入框还要对应字段或属性的名字。另外,不同的结构体或类的字段或属性的名字和类型都可能不一样。如果每一个结构体或类都要单独的制作一个编辑栏,每一个输入框都对应指定的字段或属性,如字段名称、类型等,无疑将是一个巨大的工作量。而且维护成本也很高,比如后续对某个结构体或者类添加或删除其中的某个字段,相应的也要手动修改编辑栏。本文就是提供一种可以实现动态创建结构体或类编辑栏输入框,根据结构体或类的字段名称、类型等进行创建可编辑的输入框。
二、实现
1、反射
    主要用的编程技巧是C#的反射功能,利用反射可以做下面的事情(C#本质论5.0第四版 472页):
1>:访问程序集中类型的元数据。其中包括像完整类型名和成员名这样的构造,以及对一个构造进行修饰的任何特性。
2>:使用元数据,在运行时动态调用一个类型的成员,而不是执行编译时绑定。
反射时指对程序集中的元数据进行检查的过程。在以前,当代码编译成一种机器语言时,关于代码的所有元数据(比如类型和方法名)都会被丢弃。相反,当C#编译成CIL时,它会维持关于代码的大部分元数据。除此之外,可以利用反射枚举程序集中的所有类型,找出满足特定条件的那些。
2、反射提取结构体中元数据信息
说了这么多理论的东西,我们就可以着手编写代码了,对结构体进行反射提取信息的代码如下:

 public void OnCreateAttr_OnClick(object data)
    {
        //先使用反射将结构体数据内的所有字段列举出来
        Type tempPPType = data.GetType();
        FieldInfo[] tempFI = tempPPType.GetFields();//字段
        //PropertyInfo[] tempPI = tempPPType.GetProperties();//属性
        //然后根据这些字段创建一个ui编辑条
        for (int i = 0; i < tempFI.Length; i++)
        {
            UI2D_SubObjEditorAttr tempEPPA = Instantiate(prefabEditorAttr);
            tempEPPA.transform.SetParent(ui2DCanvas.transform);
            tempEPPA.transform.localPosition = new Vector3(0, -subObjIntervalHeight * i, 0);
            tempEPPA.transform.localScale = Vector3.one;
            tempEPPA.Init(tempFI.FieldType, tempFI.Name, tempFI.GetValue(data).ToString());
            //获取字段的类型、名字和值                                                                                                          
            //MethodInfo tempMI = tempPI.GetSetMethod();//设置器为空的即是私有的
            //if (tempMI != null)
            //{
            //    Debug.Log(tempMI.Name + tempMI.IsPublic);
            //}
            // tempEPPA.Init(tempPI.PropertyType, tempPI.Name, tempPI.GetValue(curEditorRP, null).ToString());
            //添加该编辑条的编辑结束事件方法
            tempEPPA.OnEndEditor_Event += OnEndEditor_Event;
            listSubObj_EditorAttr.Add(tempEPPA);
        }
    }

述代码中用到了一个自定义的类,UI2D_SubObjEditorAttr,代码:这段代码主要是对一个输入框和Text进行封装的类,Text显示变量的名称,如图所示:创建的单个编辑条的预设,只有一个Text和输入框

using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;

public class UI2D_SubObjEditorAttr : MonoBehaviour {

    public delegate bool Editor_Event(string name, string value);
    public event Editor_Event OnEndEditor_Event;

    public string M_CurATTRName
    {
        get
        {
            return textName.text;
        }
    }

    [SerializeField]
    private Text textName;
    private InputField inputContent;

    private string lastValue;
    private string curValue;

    private bool isInitSucced = false;

        // Use this for initialization
        void Start () {
                
        }

    // Update is called once per frame
    void Update()
    {
        if (!isInitSucced) return;
    }

    /// <summary>
    /// 挂在面板上的方法
    /// </summary>
    public void UIOnEndEditor_Event()
    {
        if (null != OnEndEditor_Event)
        {
            curValue = inputContent.text;
            if (!OnEndEditor_Event(textName.text, curValue))
            {
                inputContent.text = lastValue;
            }
            else
            {
                inputContent.text = curValue;
                lastValue = curValue;
            }
        }
    }

    public void Init(Type type,string name,string vaule)
    {

        textName.text = name;
        inputContent = GetComponentInChildren<InputField>();

        inputContent.text = vaule;
        curValue = vaule;
        lastValue = curValue;
        isInitSucced = true;
    }
    public void SetValue(string value)
    {
        curValue = value;
        lastValue = curValue;
        inputContent.text = curValue;
    }
}

输入框可以显示结构体的值,并且在后期的时候对该字段的值进行修改。这里我定义了两个结构体:

[Serializable]
public struct PD_RoutePoint
{
    public int RouteID;
    public int Number;
    public double Lon;
    public float Height;
    public double Lat;
    public float Pitch_X;
    public float Yaw_Y;
    public float Roll_Z;
    public float Speed;
    public int OffsetTime;
}
[Serializable]
public struct PD_Route
{
    public int RouteID;
    public int FigherID;
    public long BaseTime;
    public string Describe;
}

3、使用方法
将定义的这两个结构体变量分别传给该方法,就可以实现根据结构体的字段自动创建该自动的编辑条,如图所示:

void Update () {
                
        if(Input.GetKeyDown(KeyCode.C))
        {
           // OnCreateAttr_OnClick(curEditorRoute);
            OnCreateAttr_OnClick(curEditorRP);
        }
}

不同的结构体变量可以动态的创建不同的编辑条,并且将默认的值赋值给每个对应的编辑条。
三、总结
1、完成了初步的将不同的结构体动态的创建编辑条的功能
2、尚未根据不同字段的类型进行编辑条细化
3、编辑条的值改变没有关联到指定的结构体变量中,也即无法动态修改结构体变量的值


未完待续。。。。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值