Unity自定义Button组件Transition

Unity自带的Button组件有三种不同的Transition(过渡)选项,分别是None, ColorTint, SpriteSwap, Animation。现在想自定义其他功能,比如在不同的状态下,按钮上的文字不同。

首先想到的是直接写一个脚本挂在Button上,实现UnityEngine.EventSystems中定义的IPointerEnterHandler, IPointerExitHandler, IPointerClickHandler这三个接口,代码如下:

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
public class MyButton1 : MonoBehaviour, IPointerEnterHandler, IPointerExitHandler, IPointerClickHandler
{
[SerializeField]
private Button button;
[SerializeField]
private Text text;

private void Start()
{
if(button == null)
{
button = GetComponent<Button>();
}
if(text == null)
{
text = GetComponentInChildren<Text>();
}
}

public void OnPointerEnter(PointerEventData eventData)
{
Debug.Log("Pointer enter");
text.text = "Pointer enter";
}

public void OnPointerExit(PointerEventData eventData)
{
Debug.Log("Pointer Exit");
text.text = "Pointer Exit";
}

public void OnPointerClick(PointerEventData eventData)
{
Debug.Log("Pointer click");
text.text = "Pointer click";
}
}

实际上Button自身已经实现了这几个接口,所以可以直接继承Button并重写这三个方法,将原来的Button组件换成MyButton2:

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
public class MyButton2 : Button
{
[SerializeField]
private Text text;

protected override void Awake()
{
base.Awake();
if(text == null)
{
text = GetComponentInChildren<Text>();
}
}

public override void OnPointerEnter(PointerEventData eventData)
{
base.OnPointerEnter(eventData);
Debug.Log("Pointer enter");
text.text = "Pointer enter";
}

public override void OnPointerExit(PointerEventData eventData)
{
base.OnPointerExit(eventData);
Debug.Log("Pointer Exit");
text.text = "Pointer Exit";
}

public override void OnPointerClick(PointerEventData eventData)
{
base.OnPointerClick(eventData);
Debug.Log("Pointer click");
text.text = "Pointer click";
}
}

这时候会发现继承自Button的MyButton2在Inspector里并不能看到text字段,这时需要对Button的编辑器显示进行扩展:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
using UnityEditor;
using UnityEditor.UI;

[CustomEditor(typeof(MyButton2), true)]
[CanEditMultipleObjects]
public class MyButton2Editor : ButtonEditor
{
private SerializedProperty text;

protected override void OnEnable()
{
base.OnEnable();
text = serializedObject.FindProperty("text");
}

public override void OnInspectorGUI()
{
base.OnInspectorGUI();
EditorGUILayout.Space();
serializedObject.Update();
EditorGUILayout.PropertyField(text);
serializedObject.ApplyModifiedProperties();
}
}

(将上面这个脚本放到Assets>Editor文件夹下,这样只是在编辑器里使用,不会被打包发布)

其实也可以直接重写Button的DoStateTransition这个方法,对应的就是Button组件显示在Inspector里的Transition:

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
public class MyButton3 : Button
{
[SerializeField]
private Text text;

protected override void Awake()
{
base.Awake();
if(text == null)
{
text = GetComponentInChildren<Text>();
}
}

protected override void DoStateTransition(SelectionState state, bool instant)
{
switch(state)
{
case SelectionState.Normal:
Debug.Log("Normal");
text.text = "Normal";
break;
case SelectionState.Pressed:
Debug.Log("Pressed");
text.text = "Pressed";
break;
case SelectionState.Highlighted:
Debug.Log("Highlited");
text.text = "Highlited";
break;
case SelectionState.Disabled:
Debug.Log("Disabled");
text.text = "Disabled";
break;
}
}
}

按照这个思路还可以实现更多的效果。