有关Editor的记录(一)

 

//ScrollView滚动卡顿优化

为什么要对ScrollView滚动卡顿做优化?是因为在使用 Unity 开发游戏的时候,经常会需要用到数据配置,方式可能是CSV、JSON等等。为了可以方便地查看修改数据,通常使用实现ScrollView在 Unity 编辑器里面以列表的形式查看数据。

当数据量大的时候,滚动视图会发现卡顿不断,测试代码如下:

?

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

using UnityEditor;

using UnityEngine;

 

public class TestListView : EditorWindow

{

    [MenuItem("Tool/Test")]

    private static void Init()

    {

        GetWindow();

    }

 

    private const int s_RowCount = 400;

    private const int s_ColCount = 30;

 

    private float m_RowHeight = 18f;

    private float m_ColWidth = 52f;

    private Vector2 m_ScrollPosition;

 

    void OnGUI()

    {

        OnDrawListView2();

    }

 

    private void OnDrawListView()

    {

        m_ScrollPosition = EditorGUILayout.BeginScrollView(m_ScrollPosition);

        for (int i = 0; i < s_RowCount; i++)

        {

            EditorGUILayout.BeginHorizontal();

            for (int j = 0; j < s_ColCount; j++)

            {

                EditorGUILayout.LabelField((i * 100 + j).ToString(), GUILayout.Width(m_ColWidth));

            }

            EditorGUILayout.EndHorizontal();

        }

        EditorGUILayout.EndScrollView();

    }

}

鼠标拖动滚动条滚动的时候,可以明显发现滚动条卡顿延迟跟着鼠标动: 

 

解决

优化的思路就是只绘制当前可视的区域,自 Unity 5.6 开始已经提供TreeView控件,自带支持大数据集, 详见https://docs.unity3d.com/560/Documentation/ScriptReference/IMGUI.Controls.TreeView.BuildRoot.html

如果还没使用 Unity 5.6,那么可以参考它的实现方式。将Layout自动布局方式改成给定矩形来绘制,这样方便知道每行的高度和总的内容高度,再根据滚动条的坐标来计算获取当前显示的起始行和结束行,只绘制需要显示的行内容。

代码修改如下:

?

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47

48

49

50

51

52

53

54

55

56

57

58

59

60

61

62

63

64

65

66

67

68

69

70

71

72

73

74

75

76

77

78

79

80

81

82

83

84

85

86

87

88

89

90

91

92

93

94

95

96

97

98

99

using UnityEditor;

using UnityEngine;

 

public class TestListView : EditorWindow

{

    [MenuItem("Tool/Test")]

    private static void Init()

    {

        GetWindow();

    }

 

    private const int s_RowCount = 400;

    private const int s_ColCount = 30;

 

    private float m_RowHeight = 18f;

    private float m_ColWidth = 52f;

    private Vector2 m_ScrollPosition;

 

    void OnGUI()

    {

        OnDrawListView2();

    }

 

    private void OnDrawListView2()

    {

        Rect totalRect = new Rect(0, 0, position.width, position.height);

        Rect contentRect = new Rect(0, 0, s_ColCount * m_ColWidth, s_RowCount * m_RowHeight);

        m_ScrollPosition = GUI.BeginScrollView(totalRect, m_ScrollPosition, contentRect);

 

        int num;

        int num2;

        GetFirstAndLastRowVisible(out num, out num2, totalRect.height);

        if (num2 >= 0)

        {

            int numVisibleRows = num2 - num + 1;

            IterateVisibleItems(num, numVisibleRows, contentRect.width, totalRect.height);

        }

 

        GUI.EndScrollView(true);

    }

 

    ///

    /// 获取可显示的起始行和结束行

    ///

    /// 起始行

    /// 结束行

    /// 视图高度

    private void GetFirstAndLastRowVisible(out int firstRowVisible, out int lastRowVisible, float viewHeight)

    {

        if (s_RowCount == 0)

        {

            firstRowVisible = lastRowVisible = -1;

        }

        else

        {

            float y = m_ScrollPosition.y;

            float height = viewHeight;

            firstRowVisible = (int)Mathf.Floor(y / m_RowHeight);

            lastRowVisible = firstRowVisible + (int)Mathf.Ceil(height / m_RowHeight);

            firstRowVisible = Mathf.Max(firstRowVisible, 0);

            lastRowVisible = Mathf.Min(lastRowVisible, s_RowCount - 1);

            if (firstRowVisible >= s_RowCount && firstRowVisible > 0)

            {

                m_ScrollPosition.y = 0f;

                GetFirstAndLastRowVisible(out firstRowVisible, out lastRowVisible, viewHeight);

            }

        }

    }

 

    ///

    /// 迭代绘制可显示的项

    ///

    /// 起始行

    /// 总可显示行数

    /// 每行的宽度

    /// 视图高度

    private void IterateVisibleItems(int firstRow, int numVisibleRows, float rowWidth, float viewHeight)

    {

        int i = 0;

        while (i < numVisibleRows)

        {

            int num2 = firstRow + i;

            Rect rowRect = new Rect(0f, (float)num2 * m_RowHeight, rowWidth, m_RowHeight);

            float num3 = rowRect.y - m_ScrollPosition.y;

            if (num3 <= viewHeight)

            {

                Rect colRect = new Rect(rowRect);

                colRect.width = m_ColWidth;

 

                for (int j = 0; j < s_ColCount; j++)

                {

                    EditorGUI.LabelField(colRect, (num2 * 100 + j).ToString());

                    colRect.x += colRect.width;

                }

            }

            i++;

        }

    }

}

再次鼠标拖动滚动条滚动的时候,可以明显发现滚动条流畅许多: 

 

编辑时的问题

因为不是绘制全部控件,那么当使用编辑框的时候,弹出的编辑控件不会跟随着滚动,如下所示:

那么就当滚动的时候,结束当前正在编辑的项吧,修改OnDrawListView2函数:

?

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

private void OnDrawListView2()

{

    Rect totalRect = new Rect(0, 0, position.width, position.height);

    Rect contentRect = new Rect(0, 0, s_ColCount * m_ColWidth, s_RowCount * m_RowHeight);

 

    // 鼠标滚动的时候,结束当前正在编辑的项

    if (Event.current.type == EventType.ScrollWheel)

    {

        if (totalRect.Contains(Event.current.mousePosition))

        {

            GUIUtility.keyboardControl = 0;

        }

    }

 

    EditorGUI.BeginChangeCheck();

    m_ScrollPosition = GUI.BeginScrollView(totalRect, m_ScrollPosition, contentRect);

    if (EditorGUI.EndChangeCheck())

    {

        // 滚动条滚动的时候,结束当前正在编辑的项

        GUIUtility.keyboardControl = 0;

    }

 

    int num;

    int num2;

    GetFirstAndLastRowVisible(out num, out num2, totalRect.height);

    if (num2 >= 0)

    {

        int numVisibleRows = num2 - num + 1;

        IterateVisibleItems(num, numVisibleRows, contentRect.width, totalRect.height);

    }

 

    GUI.EndScrollView(true);

}

自动布局

如果还是想使用自动布局方式来绘制项的话,那么可以使用GUILayout.Space来占用不需要绘制的区域。

 

///

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值