文章目录
- 自动布局占空格
- 设置自动布局控件的宽高
- 打开文件的回调
- 常用控件
- Scope的简写形式
- SerializeObject
- includeChildren
- PropertyDrawer
- ReOrderableList
- 在场景中绘制Gizmos
- OnValidate
- 使用Gizmos选中场景物体
- 自定义右键菜单menu
- 关于EventType的使用
- 重写Project 右键和Hierachy右键
- 右键创建ScriptObject
- OnOpenAsset的使用
自动布局占空格
- 在写编辑器的时候可能需要从右边开始,所以要用空格占满剩余空间
- 就可以使用
GUILayout.flexibleSpace
设置自动布局控件的宽高
- 例如
GUILayout.TextField
,它默认是没有宽度的,这时候我们就可以通过以下设定来设置 - 这些设置会重写style里面的宽高设定
GUILayout.Width
用来设置控件宽度GUILayout.Height
用来设置空间高度GUILayout.MinWidth
和GUILayout.MaxHeight
设定该控件的最大宽度和最小宽度,当拖拽窗口进行缩放的时候,该控件会缩小到最小宽度后不再变化。GUILayout.MinHeight和GUILayout.MaxHeight
也是同样的道理GUILayout.ExpandWidth
是否允许控件进行水平方向的扩展,我测试了后发现,自动布局的所有控件默认是进行水平扩展的,因此会平分整个水平宽度
GUILayout.BeginHorizontal();
createFileName = GUILayout.TextField(createFileName);
GUILayout.Button("新建"); //所有宽度平分
GUILayout.Button("重命名");
GUILayout.Button("复制");
GUILayout.Button("删除");
GUILayout.EndHorizontal();
-
- 更改代码如下
GUILayout.BeginHorizontal();
createFileName = GUILayout.TextField(createFileName,GUILayout.ExpandWidth(true));//会占据所有剩余空间
GUILayout.Button("新建",GUILayout.ExpandWidth(false));//按照style固有宽度渲染
GUILayout.Button("重命名", GUILayout.ExpandWidth(false));
GUILayout.Button("复制", GUILayout.ExpandWidth(false));
GUILayout.Button("删除", GUILayout.ExpandWidth(false));
GUILayout.EndHorizontal();
打开文件的回调
- 当我们双击某个asset文件时候,可以使用
UnityEditor.Callbacks.OnOpenAsset(0)
- 来打开窗口,代码如下
[UnityEditor.Callbacks.OnOpenAsset(0)]
static bool OpenAsset(int id, int line)
{
var obj = EditorUtility.InstanceIDToObject(id);
if (obj.GetType() == typeof(UnitSettingObject))
{
OpenWindow();
return true;
}
return false;
}
常用控件
- 在
GUI.Toggle(pos, value, label, "button")
最后的GUIStyle设置为button就可以变成toggle形式的button了 -
EditorGUI.BeginChangeCheck()
和EditorGUI.EndChangeCheck()
可以用来检测control控件是否修改 -
EditorGUI.DelayedDoubleField()
和EditorGUI.DoubleField()
的区别在于前者只有当鼠标移出输入框的时候才会返回值 -
EditorGUILayout.Foldout()
是一个带标签的折叠箭头 -
EditorGUILayout.BeginFoldoutHeaderGroup()
与EditorGUILayout.EndFoldoutHeaderGroup
相比于Foldout()
,有一个HeaderTitle,而且是一个折叠块 -
EditorUtility.OpenFolderPanel ("excel路径", LoadCenter.RootDir, "C:\\");
用于选定一个文件路径 -
obj = EditorGUILayout.ObjectField (label, obj, typeof (T), allowSceneObjects) as T;
用来选择资源
Scope的简写形式
- 通过一个结构体实现IDisposable在末尾实现EndScope
- 这样就不会忘记结尾了
public struct Vertical : IDisposable
{
public Rect Rect { get; private set; }
FlexibleTypes flexible;
public static Vertical New (FlexibleTypes flexible, GUIStyle style, params GUILayoutOption[] options)
{
var rect = EditorGUILayout.BeginVertical (style, options);
if (flexible.FlexibleBegin ())
{
GUILayout.FlexibleSpace ();
}
return new Vertical () { flexible = flexible, Rect = rect };
}
public void Dispose ()
{
if (flexible.FlexibleEnd ())
{
GUILayout.FlexibleSpace ();
}
EditorGUILayout.EndVertical ();
}
}
- 具体使用
using (GUIScope.Horizontal.New (FlexibleTypes.Begin))
{
}
SerializeObject
- unity 推荐在自定义Editor中使用这个对象来编辑数据
- 在绘制UI的时候
EditorGUI.PropertyField()
,传入SerializeProperty
即可 - 通过
stages = serializedObject.FindProperty ("stages");
可以查找到对应属性 - 这个序列化对象相当于一个流,他可以用来对多个对象的编辑,他本身会处理
Undo, prefab保存
这些。
serializeObject.update();
//draw UI
serializedObject.ApplyModifiedProperties();
- 可实际上用起来十分麻烦,代码量会增加一倍,而且用字符串的方法来索引属性,如果属性更改名字了要怎么办。
includeChildren
public static bool PropertyField (Rect position, SerializedProperty property, [DefaultValue ("false")] bool includeChildren);
- 将
includeChildren
设置为true会绘制该属性的内部字段
PropertyDrawer
- 继承
PropertyDrawer
后重写OnGUI
在内部是无法使用Layout自动布局的。会导致报错
ReOrderableList
- Unity 内部有一个
ReOrderableList
,但其实并不好用 - 对于每个Item的Height只能设定为固定值或者实现其回调
GetItemHeight()
在场景中绘制Gizmos
- 在editor模式下我们有时候需要在Scene中绘制一些形状测试用
- 这些形状不会在Game窗口中显示
private void OnDrawGizmos ()
{
foreach (var pos in allCube)
{
Gizmos.DrawCube (pos, Vector3.one);
}
}
OnValidate
- 在monobehaviour中,如果你在Inspector面板上修改了他的数据,那么就会被触发,经常用来校验数据
使用Gizmos选中场景物体
- 我们可以看到Camera在Scene场景里面绘制了一个相机的小图标,而且可以用来选中,移动相机的Transform
- 那么他是如何实现的呢?
public class PosEditCom : MonoBehaviour
{
}
public class PosEditComGizmoDrawer
{
[DrawGizmo (GizmoType.Pickable|GizmoType.Selected|GizmoType.NonSelected)]
static void DrawGizmoForMyScript (PosEditCom scr, GizmoType gizmoType)
{
Gizmos.DrawCube (scr.transform.position, Vector3.one);
}
}
- 只要给物体挂载上PosEditCom组件就可以实现绘制相应的Gizmos
自定义右键菜单menu
- unity自身有一个类是
GenericMenu
- 在Editor窗口中调用
menu.ShowAsContext()
就可以显示出来 -
menu.AddSeperator()
添加分隔符 -
menu.AddItem()
添加右键菜单的选项 - 所以我们可以利用反射和特性来实现自定义的右键menu
关于EventType的使用
if (Event.current.type == EventType.MouseDown && Event.current.button == 1)
{
menu.ShowMenu ();
Event.current.Use ();
}
重写Project 右键和Hierachy右键
- Project右键其实是和Menu的Asset菜单一样的。
- 而Hierachy的右键其实是和
GameObject
一样的 - 所以我们要扩展的时候,只要给类的静态方法添加
MenuItem("Assets/")
- 如果要重写,则用到
EditorApplication.projectWindowItemOnGUI+=OnProjectGUI
EditorApplication.hierarchyWindowItemOnGUI += OnHierarchyGUI;
- 代码如下:
[MenuItem ("Assets/TestMenu01/TestMenu04")]
static void TestMenu04 ()
{
Debug.Log ("点击了TestMenu04");
}
[In
itializeOnLoadMethod]
static void StartInitializeOnLoadMethod ()
{
EditorApplication.hierarchyWindowItemOnGUI += OnHierarchyGUI;
}
static void OnHierarchyGUI (int instanceID, Rect selectionRect)
{
if (Event.current != null && selectionRect.Contains (Event.current.mousePosition)
&& Event.current.button == 1 && Event.current.type <= EventType.MouseUp)
{
GameObject selectedGameObject = EditorUtility.InstanceIDToObject (instanceID) as GameObject;
//这里可以判断selectedGameObject的条件
if (selectedGameObject)
{
Vector2 mousePosition = Event.current.mousePosition;
EditorUtility.DisplayPopupMenu (new Rect (mousePosition.x, mousePosition.y, 0, 0), "Window/Test", null);
Event.current.Use ();
}
}
}
右键创建ScriptObject
[CreateAssetMenu (menuName = "xuhaitao/personInfo")]
public class shishi : ScriptableObject
{
public string namee;
public int age;
public Image img;
}
OnOpenAsset的使用
-
OnOpenAssetAttribute
是一个特性 - 当你双击某个asset文件的时候就会调用这个特性修饰的静态方法
[OnOpenAssetAttribute(1)]
public static bool step1(int instanceID, int line)
{
string name = EditorUtility.InstanceIDToObject(instanceID).name;
Debug.Log("Open Asset step: 1 (" + name + ")");
return false; // we did not handle the open
}