Unity实现类似VS导航功能

发表于2015-10-26
评论0 1.3k浏览

相信大家都遇到过这样一个问题:在Unity中查找最近访问过的文件、资源、对象时,当工程量很大、文件目录层次很多的时候,总是会不知所措,需要点击很多次才会找到想要的资源、对象。这在实际开发中很浪费时间,不知道为什么Unity官方没有实现类似“VS中的向前、向后导航”功能。
本文即在Unity中实现一个类似于VS中的导航功能。本文将介绍如何实现、使用该功能。

实现方法

实现导航功能主要分为两块实现:

  • 实现访问内容的存储
  • 实现导航功能的界面和导航效果
    以下将分别介绍如何实现。

存储访问内容

1.利用委托机制实现定时刷新功能
代码如下所示:

static NavigationSelectionHistory(){EditorApplication.update += TrackSelectionChange;}

以上代码会以unity中的update频率(默认100次每秒)调用方法TrackSelectionChange。那么,我们只需要在方法TrackSelectionChange中实现对选中数据的存储,即可以完成访问记录的存储。

2.定时刷新时将数据存储到列表中

private const int MAX_HISTORY_COUNT = 100;public static List<Object> PreviousSelectionList = new List<Object>(); // Use this for initializationpublic static void TrackSelectionChange(){//判断当前list是否为null,如果为null,则移除for (var i = 0; i < PreviousSelectionList.Count; ){if (PreviousSelectionList[i] == null){PreviousSelectionList.RemoveAt(i);}else{i++;}}if (Selection.objects.Any()){//有选中的object,取第一个objectvar selectionObject = Selection.objects[0];if (selectionObject != null &&(PreviousSelectionList.Count == 0 || !IsSelectionEqual(PreviousSelectionList[0], selectionObject))){var exitIndex = PreviousSelectionList.FindIndex(x => IsSelectionEqual(x, selectionObject));if (exitIndex != -1){//存在相同的对象,则删除PreviousSelectionList.RemoveAt(exitIndex);}//插入当前对象PreviousSelectionList.Insert(0,selectionObject);//PreviousSelectionList.Insert(0,selectionObject);//删除对应的对象if (PreviousSelectionList.Count > MAX_HISTORY_COUNT){//删除最老的对象PreviousSelectionList.RemoveRange(MAX_HISTORY_COUNT, PreviousSelectionList.Count - MAX_HISTORY_COUNT);}}}}private static bool IsSelectionEqual(Object sel1, Object sel2){if (sel1 == null || sel2 == null || sel1 != sel2){return false;}else{return true;}}

代码注释的很清晰,主要功能由定时刷新函数TrackSelectionChange完成。获得选中对象是通过代码“var selectionObject = Selection.objects[0];”完成。
注:默认每次只选中一个对象,如果选中多个对象,只存储第一个对象。

导航功能实现

等得到数据之后,便是实现导航界面,完成导航功能了。
实现的导航效果如下所示:

具体窗口绘制的图标、美化这里不会赘述。这里展示出主要的实现代码。
1.显示窗口代码(通过menu或者快捷键实现)

[MenuItem("Navigation/显示窗口 &E",false,124)]private static void NavigationShowWindow(){Debug.Log("显示窗口");//window = EditorWindow.GetWindow<NavigationWindow>();window = EditorWindow.GetWindow<NavigationWindow>();window.wantsMouseMove = true;window.title = "导航窗口";window.Show();window.Focus();}

2.窗口绘制界面的代码

private void OnGUI(){ShowNavigationButton();//绘制buttonif (window != null){GUILayout.BeginArea(new Rect(10, 60, window.position.width-10, 400));}else{GUILayout.BeginArea(new Rect(10, 60, 400, 400));}ShowSelectionHistoryList();//绘制列表GUILayout.EndArea();}

鉴于button绘制和业务逻辑实现比较啰嗦,且没啥技术难点,这里不再列出来,有需求的可以联系我。下文将列出列表显示。
3.绘制列表代码

private void ShowSelectionHistoryList(){GUILayout.Label("最近访问对象列表");GUILayout.Space(ROW_GAP);_scrollPosition = EditorGUILayout.BeginScrollView(_scrollPosition, GUIStyle.none, GUI.skin.verticalScrollbar, GUILayout.ExpandWidth(true), GUILayout.ExpandHeight(true));int index = 0;foreach (var keyValuePair in NavigationSelectionHistory.PreviousSelectionList){//显示列表EditorGUILayout.BeginHorizontal((index == selectedIndex) ? selectedLineGuiStyle : regularLineGuiStyle);GUIStyle style_check = new GUIStyle();style_check.margin.top = 3;style_check.margin.right = 5;GUIStyle style = new GUIStyle();style.margin.top = 3;if (index == lastClickIndex){//显示选中图标GUILayout.Label(Checked_Icon, style_check, GUILayout.Width(TEXTURE_WIDTH), GUILayout.Height(TEXTURE_HEIGHT));}else{GUILayout.Label("", style_check, GUILayout.Width(TEXTURE_WIDTH), GUILayout.Height(TEXTURE_HEIGHT));}GUILayout.Label(UnityUIUtility.GetIconForFile(keyValuePair.Value), style, GUILayout.Width(TEXTURE_WIDTH), GUILayout.Height(TEXTURE_HEIGHT));GUILayout.Label(keyValuePair.Key.name, ListTextGuiStyle, GUILayout.ExpandWidth(true),GUILayout.Height(TEXTURE_HEIGHT));EditorGUILayout.EndHorizontal();index++;}EditorGUILayout.EndScrollView();}

代码中注释比较详细,这里不再做解释。其中某些图标的显示、列表中着色等都属于界面绘制功能。这里没有贴出代码。大家可以自己尝试实现。

结论

小结一下,通过以下的思路和主要代码,便能够实现类似VS中的导航功能。
鉴于本人最近在研究Unity插件相关工作,感兴趣的可以一块讨论学习。

如社区发表内容存在侵权行为,您可以点击这里查看侵权投诉指引

标签: