自定义Inspector 面板编辑器

爷,独闯天下 提交于 2019-12-03 14:06:20

Chinar blog www.chinar.xin

自定义Inspector 面板编辑器


本文提供全流程,中文翻译。

Chinar 的初衷是将一种简单的生活方式带给世人

使有限时间 具备无限可能

Chinar ―― 心分享、心创新!

助力快速了解编辑器扩展如何使我们高效的工作

为初学者节省宝贵的时间,避免采坑!

----------


全文高清图片,点击即可放大观看 (很多人竟然不知道)


1

Intro —— 介绍


有些插件会写大量的编辑器类,来便于开发者对插件属性的调整。

这其中就有很多对 Inspector面板重新绘制,使开发者可以可视化的调整相应参数
举个例子
在这里插入图片描述


2

Custom Inspector Editor ―― 自定义检视面板编辑器


众所周知,一个继承 MonBehaviour 类的脚本

我们可以通过 Public 来使其中变量显示在Inspector面板,以便于我们对其参数值进行调整

1 —— 首先,我们自定义一个要被扩展的目标脚本

需继承 MonBehaviour

 public class ChinarInspector: MonoBehaviour
{
    public int A;   //字段A
    public string B;//字段B
}

举个例子 挂载脚本后,Inspector 所示:
在这里插入图片描述

2 —— 需要一个与之对应的编辑器脚本,对目标脚本在 Inspector 面板上的显示,进行重写

该脚本需要放在 Editor 文件夹中,并且要继承 Editor

using UnityEditor;


[CustomEditor(typeof(ChinarInspector))] //特性:自定义编辑类 ChinarInspector
public class ChinarEditor : Editor      //需要继承 Editor
{
    private ChinarInspector chinarInspector; // 类对象


    private void OnEnable()
    {
        chinarInspector = (ChinarInspector) target; //获取当前编辑自定义Inspector的对象(官方解释授检查的对象)
    }


    //通过对该方法的重写,可以对 Inspector 面板重新绘制,添加自己自定义GUI
    //既然说的自定义UI,就会覆盖我们关联脚本本身在面板的绘制
    public override void OnInspectorGUI()
    {
        //不写任何代码,ChinarInspector的面板上不出现任何属性
    }
}

OnEnable 函数,在 Editor 类中与 MonoBehavior 类中是完全不同的

调用时机 Editor MonoBehavior
OnEnable 1:每次聚焦 Unity 引擎窗口时 脚本挂载的 GameObject 对象激活时
OnEnable 2:点击 脚本挂载的 GameObject 对象时
OnEnable 3:点击 Inspector,其他模块(例如scene面板)

举个例子

关联后的自定义脚本前在 Inspector 如下所示:
在这里插入图片描述


3

EditorGUILayout ―― 编辑器界面自动布局


  • EditorGUILayout :编辑器 UI 自动布局类,绘制的所有控件都具备自动布局(UI自适应)效果

GUILayout 的差异:

  • 拥有部分编辑器专用控件,
  • 只能运行在编辑器内
  • 自适应性较强

英文好的直接:EditorGUILayout 官方API链接

EditorGUILayout 只能在编辑器中使用,发布时是不会被打包

简单的示例,来向大家演示 EditorGUILayout 如何使 Inspector 面板更加直观,易用

3.1

EditorGUILayout.LabelField ―― 制作一个标签字段(通常用于显示只读信息)


举个例子

在这里插入图片描述

using UnityEditor;

/// <summary>
/// 编辑器类:用于对 ChinarInspector 做编辑器处理
/// </summary>
[CustomEditor(typeof(ChinarInspector))] //关联自定义编辑器脚本 ChinarInspector
public class ChinarEditor : Editor //自定义编辑器需要继承Editor
{
    private ChinarInspector chinarInspector; //关联目标对象

    private void OnEnable()
    {
        chinarInspector = (ChinarInspector) target; //获取当前编辑自定义 Inspector 的对象
    }

    /// <summary>
    /// 重绘 Inspector
    /// </summary>
    public override void OnInspectorGUI()
    {
        //制作一个标签字段(通常用于显示只读信息)
        EditorGUILayout.LabelField("定义信息","它只读不可写"); 
        //参数:label1标签字段前面的标签  label2显示在右侧的标签  --无返回
    }
}

3.2

EditorGUILayout.SelectableLabel ―― 可选择标签(通常用于显示只读信息,可以被复制粘贴)


举个例子

在这里插入图片描述

using UnityEditor;

/// <summary>
/// 编辑器类:用于对 ChinarInspector 做编辑器处理
/// </summary>
[CustomEditor(typeof(ChinarInspector))] //关联自定义编辑器脚本 ChinarInspector
public class ChinarEditor : Editor //自定义编辑器需要继承Editor
{
    private ChinarInspector chinarInspector; //关联目标对象

    private void OnEnable()
    {
        chinarInspector = (ChinarInspector) target; //获取当前编辑自定义 Inspector 的对象
    }

    /// <summary>
    /// 重绘 Inspector
    /// </summary>
    public override void OnInspectorGUI()
    {
        //可选择标签(通常用于显示只读信息,可以被复制粘贴)
        //参数:text显示的文本   无返回值
        EditorGUILayout.SelectableLabel("此标签可以被复制");
    }
}

3.3

EditorGUILayout.TextField ―― 文本字段 (可以有默认值,有返回值,并且可以在Inspector面板赋值)


举个例子

在这里插入图片描述

using UnityEditor;

/// <summary>
/// 编辑器类:用于对 ChinarInspector 做编辑器处理
/// </summary>
[CustomEditor(typeof(ChinarInspector))] //关联自定义编辑器脚本 ChinarInspector
public class ChinarEditor : Editor //自定义编辑器需要继承Editor
{
    private ChinarInspector chinarInspector; //关联目标对象

    private void OnEnable()
    {
        chinarInspector = (ChinarInspector) target; //获取当前编辑自定义 Inspector 的对象
    }

    /// <summary>
    /// 重绘 Inspector
    /// </summary>
    public override void OnInspectorGUI()
    {
        //文本字段 可读 可写
        chinarInspector.gameObject.name =  EditorGUILayout.TextField("定义信息", chinarInspector.gameObject.name);
         //参数:label1标签字段前面的标签  label2默认显示文本  --有返回值
    }
}

3.4

EditorGUILayout.PasswordField ―― 密码字段(通常用于显示只读信息,可以被复制粘贴)


举个例子
在这里插入图片描述

using UnityEditor;

/// <summary>
/// 编辑器类:用于对 ChinarInspector 做编辑器处理
/// </summary>
[CustomEditor(typeof(ChinarInspector))] //关联自定义编辑器脚本 ChinarInspector
public class ChinarEditor : Editor //自定义编辑器需要继承Editor
{
    private ChinarInspector chinarInspector; //关联目标对象

    private void OnEnable()
    {
        chinarInspector = (ChinarInspector) target; //获取当前编辑自定义 Inspector 的对象
    }

    private string text;
    /// <summary>
    /// 重绘 Inspector
    /// </summary>
    public override void OnInspectorGUI()
    {
        //创建密码字段并可视化在密码字段有什么键入
        //参数:label开关按钮前面的可选标签  password编辑的密码 有返回值
        text = EditorGUILayout.PasswordField("Type Something:", text);
        EditorGUILayout.LabelField("显示密码",text);
    }
}

3.5

EditorGUILayout.IntField/FloatField ―― 整数字段


举个例子

在这里插入图片描述

using UnityEditor;

/// <summary>
/// 编辑器类:用于对 ChinarInspector 做编辑器处理
/// </summary>
[CustomEditor(typeof(ChinarInspector))] //关联自定义编辑器脚本 ChinarInspector
public class ChinarEditor : Editor //自定义编辑器需要继承Editor
{
    private ChinarInspector chinarInspector; //关联目标对象

    private void OnEnable()
    {
        chinarInspector = (ChinarInspector) target; //获取当前编辑自定义 Inspector 的对象
    }

    private int intNumber = 0;//输入的Int默认值和返回值
    private float floatNumber = 0;//输入Float默认值和返回值
    /// <summary>
    /// 重绘 Inspector
    /// </summary>
    public override void OnInspectorGUI()
    {
        intNumber = EditorGUILayout.IntField("输入Int类型:", intNumber);// 整数字段:返回整数,由用户输入的值(参数:标签名,默认整型字段)
        floatNumber = EditorGUILayout.FloatField("输入Float类型:", floatNumber);//浮点数字段:返回小数,由用户输入的值(参数:标签名,默认浮点数字段)
    }
}

3.6

EditorGUILayout.Slider /IntSlider/MinMaxSlider―― 滑动条/整数滑动条/最小最大滑动条


举个例子
在这里插入图片描述

using UnityEditor;

/// <summary>
/// 编辑器类:用于对 ChinarInspector 做编辑器处理
/// </summary>
[CustomEditor(typeof(ChinarInspector))] //关联自定义编辑器脚本 ChinarInspector
public class ChinarEditor : Editor //自定义编辑器需要继承Editor
{
    private ChinarInspector chinarInspector; //关联目标对象

    private void OnEnable()
    {
        chinarInspector = (ChinarInspector) target; //获取当前编辑自定义 Inspector 的对象
    }

    private int intNumber = 0;//Intslider默认值和返回值
    private float floatNumber = 0;//slider默认值和返回值

    float minVal = -10.0f;//左侧默认值
    float minLimit = -20.0f;//最小值
    float maxVal = 10.0f;//右侧默认值
    float maxLimit = 20.0f;//最大值
    /// <summary>
    /// 重绘 Inspector
    /// </summary>
    public override void OnInspectorGUI()
    {
        //整数滑动条
        intNumber = EditorGUILayout.IntSlider("血量百分比", intNumber, 0, 100); //绘制 Intslider 滑动条 参数(标签名,value编辑的值,最小值,最大值)
        //浮点数滑动条
        floatNumber = EditorGUILayout.Slider("血量百分比", floatNumber, 0, 100); //绘制 slider 滑动条 参数(标签名,value编辑的值,最小值,最大值)
        //最小最大滑动条
        EditorGUILayout.MinMaxSlider(ref minVal,ref maxVal, minLimit, maxLimit);  //参数:(左侧默认值,右侧默认值,最小值,最大值)
        EditorGUILayout.LabelField("最小为:",minVal.ToString());
        EditorGUILayout.LabelField("最大为:", maxVal.ToString());
    }
}

3.7

EditorGUILayout.Popup/EnumPopup/IntPopup―― 弹出选择菜单/枚举弹出选择菜单/整数弹出选择菜单


举个例子
在这里插入图片描述

using UnityEditor;

/// <summary>
/// 编辑器类:用于对 ChinarInspector 做编辑器处理
/// </summary>
[CustomEditor(typeof(ChinarInspector))] //关联自定义编辑器脚本 ChinarInspector
public class ChinarEditor : Editor //自定义编辑器需要继承Editor
{
    private ChinarInspector chinarInspector; //关联目标对象

    private void OnEnable()
    {
        chinarInspector = (ChinarInspector) target; //获取当前编辑自定义 Inspector 的对象
    }

    /// <summary>
    ///Popup 看这里:Popup弹出选择菜单
    /// </summary>
    public string[] PlayerNames = new string[] { "世界好小姐", "中国好声音甲组冠军", "Chinar网站创始淫" };
    public string PlayerName;   //称谓 
    public int selectedIndex = 0;//字段选项的索引

    /// <summary>
    /// IntPopup 看这里:IntPopup弹出选择菜单
    /// </summary>
    public string[] ageNameList = new string[] { "Chinar小学一年级时", "Chinar小学二年级时", "Chinar小学三年级时", "Chinar小学四年级时" };
    public int[] ages = new int[] { 20, 21, 22, 23 };
    public int selectedAgeIndex = 0;//字段选项的索引

    /// <summary>
    /// EnumPopup看这里:EnumPopup弹出选择菜单
    /// </summary>
    public enum GreatType//创建预制体的枚举类型
    {
        CUBE = 0,//Cube类型
        SPHERE = 1,//Sphere类型
        PLANE = 2//Plane类型
    }

    private GreatType op;
    /// <summary>
    /// 重绘 Inspector
    /// </summary>
    public override void OnInspectorGUI()
    {
        //Popup弹出选择菜单
        selectedIndex = EditorGUILayout.Popup("选择菜单", selectedIndex, PlayerNames);
        //参数:label字段前面可选标签  selectedIndex字段选项的索引, 菜单集合数组  有返回值 (字段选项的索引)

        //IntPopup 整数弹出选择菜单
        selectedAgeIndex = EditorGUILayout.IntPopup("整数选择菜单: ", selectedAgeIndex, ageNameList, ages);
        EditorGUILayout.LabelField("Chinar这个时候年纪是", selectedAgeIndex.ToString());
        //参数:label字段前面的可选标签  selectedValue字段选项的索引 displayOptions弹出菜单項数组 optionValues每个选项带有值的数组。。
        //返回:int,用户选择的选项的值

        //EnumPopup枚举弹出选择菜单(效果同上)
        op = (GreatType)EditorGUILayout.EnumPopup("Primitive to create:", op);
        //参数:label字段前面的可选标签 默认枚举类型。
        //返回:枚举类型
    }
}

3.8

EditorGUILayout (Horizontal/Vertical) ―― 横向布局/纵向布局


using UnityEngine;

/// <summary>
/// 要被扩展的目标脚本
/// </summary>
public class ChinarInspector : MonoBehaviour
{
    
}

举个例子
在这里插入图片描述

using UnityEngine;
using UnityEditor;

/// <summary>
/// 编辑器类:用于对 ChinarInspector 做编辑器处理
/// </summary>
[CustomEditor(typeof(ChinarInspector))] //关联自定义编辑器脚本 ChinarInspector
public class ChinarEditor : Editor //自定义编辑器需要继承Editor
{
    private ChinarInspector chinarInspector; //关联目标对象

    private void OnEnable()
    {
        chinarInspector = (ChinarInspector) target; //获取当前编辑自定义 Inspector 的对象
    }

    /// <summary>
    /// 重绘 Inspector
    /// </summary>
    public override void OnInspectorGUI()
    {
        ChinarHorizontalLayout(); //横向布局
    }

    /// <summary>
    /// 横向布局写法
    /// </summary>
    private void ChinarHorizontalLayout()
    {
        EditorGUILayout.BeginHorizontal(); //开启一个横向布局 ——(注意一个设置布局的开始 对应一个布局的结束  EditorGUILayout.EndHorizontal)
        EditorGUILayout.Space(); //空行 (我们设置的横向布局 所以现在的空行 是横向的空行)
        EditorGUILayout.LabelField("位置1"); //设置文本描述
        EditorGUILayout.Space();
        EditorGUILayout.Space();
        EditorGUILayout.LabelField("位置2");
        EditorGUILayout.EndHorizontal(); //注意一个设置布局的开始 对应一个布局的结束 (与上面的 EditorGUILayout.BeginHorizontal() 对应起来)
    }
}

纵向布局效果图 如下所示:
举个例子

在这里插入图片描述

using UnityEngine;
using UnityEditor;

/// <summary>
/// 编辑器类:用于对 ChinarInspector 做编辑器处理
/// </summary>
[CustomEditor(typeof(ChinarInspector))] //关联自定义编辑器脚本 ChinarInspector
public class ChinarEditor : Editor //自定义编辑器需要继承Editor
{
    private ChinarInspector chinarInspector; //关联目标对象

    private void OnEnable()
    {
        chinarInspector = (ChinarInspector) target; //获取当前编辑自定义 Inspector 的对象
    }

    /// <summary>
    /// 重绘 Inspector
    /// </summary>
    public override void OnInspectorGUI()
    {
        ChinarVerticalLayout(); //纵向布局
    }

    /// <summary>
    /// 纵向布局写法
    /// </summary>
    private void ChinarVerticalLayout()
    {
        EditorGUILayout.BeginVertical(); //开启一个纵向布局 ——(注意一个设置布局的开始 对应一个布局的结束  EditorGUILayout.BeginVertical)
        EditorGUILayout.Space(); //空行 (我们设置的纵向布局 所以现在的空行 是纵向的空行)
        EditorGUILayout.LabelField("位置1"); //设置文本描述
        EditorGUILayout.Space();
        EditorGUILayout.Space();
        EditorGUILayout.LabelField("位置2");
        EditorGUILayout.EndVertical(); //注意一个设置布局的开始 对应一个布局的结束 (与上面的 EditorGUILayout.BeginVertical() 对应起来)
    }
}

3.9

EditorGUILayout.ColorField ―― 颜色字段


举个例子

在这里插入图片描述

using UnityEngine;
using UnityEditor;

/// <summary>
/// 编辑器类:用于对 ChinarInspector 做编辑器处理
/// </summary>
[CustomEditor(typeof(ChinarInspector))] //关联自定义编辑器脚本 ChinarInspector
public class ChinarEditor : Editor //自定义编辑器需要继承Editor
{
  using UnityEditor;
using UnityEngine;

/// <summary>
/// 编辑器类:用于对 ChinarInspector 做编辑器处理
/// </summary>
[CustomEditor(typeof(ChinarInspector))] //关联自定义编辑器脚本 ChinarInspector
public class ChinarEditor : Editor //自定义编辑器需要继承Editor
{
    private ChinarInspector chinarInspector; //关联目标对象

    private void OnEnable()
    {
        chinarInspector = (ChinarInspector) target; //获取当前编辑自定义 Inspector 的对象
    }

    private Color color = Color.black;

    /// <summary>
    /// 重绘 Inspector
    /// </summary>
    public override void OnInspectorGUI()
    {
        color = EditorGUILayout.ColorField("颜色", color);
        //参数:label字段前面的可选标签  value编辑的值
        //返回:Color,由用户输入的值

        chinarInspector.GetComponent<Renderer>().material.color = color;//目标对象的颜色根据上面我们自定义的颜色所改变
    }
}
}

3.10

EditorGUILayout.CurveField ―― 曲线动画编辑器


举个例子

在这里插入图片描述

using UnityEditor;
using UnityEngine;

/// <summary>
/// 编辑器类:用于对 ChinarInspector 做编辑器处理
/// </summary>
[CustomEditor(typeof(ChinarInspector))] //关联自定义编辑器脚本 ChinarInspector
public class ChinarEditor : Editor //自定义编辑器需要继承Editor
{
    private ChinarInspector chinarInspector; //关联目标对象

    private void OnEnable()
    {
        chinarInspector = (ChinarInspector) target; //获取当前编辑自定义 Inspector 的对象
    }

    AnimationCurve scaleCurve = AnimationCurve.Linear(0, 0, 1, 1); //(时间开始 : float, 数值开始 : float, 时间结束 : float, 数值结束 : float)
    /// <summary>
    /// 重绘 Inspector
    /// </summary>
    public override void OnInspectorGUI()
    {
        scaleCurve = EditorGUILayout.CurveField("scaleCurve", scaleCurve);//参数一标签名,默认曲线 返回值 动画曲线
        var scaleValue = scaleCurve.Evaluate(0.5f);//:利用时间获取曲线的值   参数时间 横轴为时间轴 Y轴为对应的返回值
        chinarInspector.transform.localScale = new Vector3(scaleValue, scaleValue, scaleValue);//对象的localScale赋值
    }
}

3.11

EditorGUILayout.Foldout &EditorGUILayout.HelpBox ―― 树节点 下拉框显示 &显示一个提示框


举个例子
在这里插入图片描述

using UnityEditor;
using UnityEngine;

/// <summary>
/// 编辑器类:用于对 ChinarInspector 做编辑器处理
/// </summary>
[CustomEditor(typeof(ChinarInspector))] //关联自定义编辑器脚本 ChinarInspector
public class ChinarEditor : Editor //自定义编辑器需要继承Editor
{
    private ChinarInspector chinarInspector; //关联目标对象

    private void OnEnable()
    {
        chinarInspector = (ChinarInspector) target; //获取当前编辑自定义 Inspector 的对象
    }

    private bool isList;
    /// <summary>
    /// 重绘 Inspector
    /// </summary>
    public override void OnInspectorGUI()
    {
        isList = EditorGUILayout.Foldout(isList, "List");//树节点 下拉框显示 参数(1 bool(true 为下拉 ,false 上折)2 标签描述)
        if (isList)
        {
            //显示一个提示框 参数(标签显示,枚举(  // None = 0, Info = 1,Warning = 2,Error = 3))
            EditorGUILayout.HelpBox("HelpBox  None :演示", MessageType.None);
            EditorGUILayout.HelpBox("HelpBox   Info :演示", MessageType.Info); 
            EditorGUILayout.HelpBox("HelpBox   Warning :演示", MessageType.Warning); 
            EditorGUILayout.HelpBox("HelpBox   Error :演示", MessageType.Error); 
        }
    }
}

3.12

EditorGUILayout.BeginToggleGroup&EditorGUILayout.Toggle/ToggleLeft ―― 开关组 &右开关/左开关


举个例子
在这里插入图片描述

using UnityEditor;
using UnityEngine;

/// <summary>
/// 编辑器类:用于对 ChinarInspector 做编辑器处理
/// </summary>
[CustomEditor(typeof(ChinarInspector))] //关联自定义编辑器脚本 ChinarInspector
public class ChinarEditor : Editor //自定义编辑器需要继承Editor
{
    private ChinarInspector chinarInspector; //关联目标对象

    private void OnEnable()
    {
        chinarInspector = (ChinarInspector) target; //获取当前编辑自定义 Inspector 的对象
    }

    private bool isToogleGroup;//创建开关组
    private bool isToogleRight;//右侧开关bool
    private bool isToogleLeft;//左侧开关bool
    /// <summary>
    /// 重绘 Inspector
    /// </summary>
    public override void OnInspectorGUI()
    {
        isToogleGroup = EditorGUILayout.BeginToggleGroup("开关组", isToogleGroup);//创建开关组 :参数 标签名,默认bool类型 返回值 bool
        isToogleRight = EditorGUILayout.Toggle("开关在右侧", isToogleRight);//创建一个切换区域,其中的开关在右边,标签立即在它的左边 :参数 标签名,默认bool类型 返回值 bool
        isToogleLeft = EditorGUILayout.ToggleLeft("开关在左侧", isToogleLeft);//ToggleLeft():创建一个切换区域,其中的开关在左边,标签立即在它的右边。
        EditorGUILayout.EndToggleGroup();//一个BeginToggleGroup 对应一个EndToggleGroup语句 (固定写法)
    }
}

3.13

EditorGUILayout.ObjectField ―― 物体字段(拖拽物体或拾取器选择物体)


举个例子

在这里插入图片描述

using UnityEditor;
using UnityEngine;

/// <summary>
/// 编辑器类:用于对 ChinarInspector 做编辑器处理
/// </summary>
[CustomEditor(typeof(ChinarInspector))] //关联自定义编辑器脚本 ChinarInspector
public class ChinarEditor : Editor //自定义编辑器需要继承Editor
{
    private ChinarInspector chinarInspector; //关联目标对象

    private void OnEnable()
    {
        chinarInspector = (ChinarInspector) target; //获取当前编辑自定义 Inspector 的对象
    }

    Object obj;
    /// <summary>
    /// 重绘 Inspector
    /// </summary>
    public override void OnInspectorGUI()
    {
        obj = EditorGUILayout.ObjectField("obj", obj, typeof(Object));
        //label字段前面的可选标签   obj字段显示的物体   objType物体的类型    allowSceneObjects允许指定场景物体..
        //返回:Object,用户设置的物体
    }
}

3.14

GUILayout.Button ―― 添加一个按钮


举个例子

在这里插入图片描述

using UnityEditor;
using UnityEngine;

/// <summary>
/// 编辑器类:用于对 ChinarInspector 做编辑器处理
/// </summary>
[CustomEditor(typeof(ChinarInspector))] //关联自定义编辑器脚本 ChinarInspector
public class ChinarEditor : Editor //自定义编辑器需要继承Editor
{
    private ChinarInspector chinarInspector; //关联目标对象

    private void OnEnable()
    {
        chinarInspector = (ChinarInspector) target; //获取当前编辑自定义 Inspector 的对象
    }

    Object obj;
    /// <summary>
    /// 重绘 Inspector
    /// </summary>
    public override void OnInspectorGUI()
    {
        obj = EditorGUILayout.ObjectField("obj", obj, typeof(Object));
        //label字段前面的可选标签   obj字段显示的物体   objType物体的类型    allowSceneObjects允许指定场景物体..
        //返回:Object,用户设置的物体

        if (GUILayout.Button("DebugObjName"))//创建一个按钮 参数:标签名 返回值bool
        {
            Debug.Log("调用按钮成功 obj的名字为"+ obj.name);
        }

    }
}

支持

May Be ―― 开发者,总有一天要做的事!


拥有自己的服务器,无需再找攻略

Chinar 提供一站式《零》基础教程

使有限时间 具备无限可能!

先点击领取 ―― 阿里全产品优惠券 (享受最低优惠)



Chinar 免费服务器、建站教程全攻略!( Chinar Blog )



END

本博客为非营利性个人原创,除部分有明确署名的作品外,所刊登的所有作品的著作权均为本人所拥有,本人保留所有法定权利。违者必究

对于需要复制、转载、链接和传播博客文章或内容的,请及时和本博主进行联系,留言,Email: ichinar@icloud.com

对于经本博主明确授权和许可使用文章及内容的,使用时请注明文章或内容出处并注明网址

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!