UGUI源码分析-拓展Button点击缩放功能

1.本文内容概述

对于原版本的Button添加按钮缩放比较困难的问题,开发了一个基于dotween的缩放按钮统一插件功能。

主要解决的痛点

  1. Button使用Animation实现各种效果,动画必须要求各个按钮节点相同。
  2. Button的效果比较重量级,对程序来说不好维护
  3. Button不是很灵活,一般游戏工程的按钮比较简单和统一,不需要如此庞大复制的配置
    以上几点我开发了一个ScaleButton做完UGUI的补充插件。而且可以不断的按照此方法拓展新的功能。分析下UGUI-Button的一些源码,点击效果如何实现的效果的细节。添加一个拓展实现缩放功能(DoTween插件实现的),并且增加一个ScaleButton的编辑器脚本和一个快捷创建按钮的页签。

2.Button按钮的代码分析

Button的效果主要是Selectable类的DoStateTransition(SelectionState state, bool instant)方法控制状态的切换。

Selectable.cs
1
2
3
4
5
6
7
8
protected enum SelectionState
{
Normal, // 默认状态
Highlighted, //鼠标悬浮
Pressed, //点击
Selected, //选中
Disabled //禁用
}
我们只要实现这个方法,对应状态做对应的变化就行。

3.如何实现点击动画效果

使用doTween会让我们的工作变得简单。这里使用dotween的插件来做一个简单的缩放功能。

4.实现一个按钮缩放的功能的按钮–UIScaleButton

基于上面的分析我们创建UIScaleButton,重写DoStateTransition方法。

注意在OnDestroy时对Dotween进行删除

UIScaleButton.cs
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
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.EventSystems;
using UnityEngine.UI;
using DG.Tweening;
using Unity.VisualScripting;

namespace Rainbow.UI
{
public class UIScaleButton : Button
{
[SerializeField]
public float m_ScaleUp = 1f;
[SerializeField]
public float m_ScaleDown = 0.95f;
[SerializeField]
Transform m_Target;

private float transScale = 1f;

Tween tween;

protected override void DoStateTransition(SelectionState state, bool instant)
{
base.DoStateTransition(state, instant);
switch (state)
{
case SelectionState.Normal:
transScale = m_ScaleUp;
break;
case SelectionState.Pressed:
transScale = m_ScaleDown;
break;
default:
transScale = m_ScaleUp;
break;
}
DoScale();

}

void DoScale()
{
Transform tweenTrans = m_Target ? m_Target : transform;
tween = tweenTrans.DOScale(Vector3.one * transScale, 0.3f).SetEase(Ease.OutBack);
}

protected override void OnDestroy()
{
base.OnDestroy();
tween.Kill();
}

}
}

另外为UIScaleButton添加一个编辑器脚本。

UIScaleButtonEditor.cs
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
using UnityEditor;
using UnityEditor.UI;
using UnityEngine;

namespace Rainbow.UI
{
[CustomEditor(typeof(UIScaleButton))]
[DisallowMultipleComponent]
public class UIScaleButtonEditor : ButtonEditor
{
SerializedProperty m_ScaleUpProperty;
SerializedProperty m_ScaleDownProperty;
SerializedProperty m_TargetProperty;
protected override void OnEnable()
{
base.OnEnable();
m_ScaleUpProperty = serializedObject.FindProperty("m_ScaleUp");
m_ScaleDownProperty = serializedObject.FindProperty("m_ScaleDown");
m_TargetProperty = serializedObject.FindProperty("m_Target");
}

public override void OnInspectorGUI()
{
base.OnInspectorGUI();
serializedObject.Update();
EditorGUILayout.PropertyField(m_ScaleUpProperty);
EditorGUILayout.PropertyField(m_ScaleDownProperty);
EditorGUILayout.PropertyField(m_TargetProperty);
serializedObject.ApplyModifiedProperties();
}
}
}

添加一个快捷创建UIScaleButton的选项。

UGUIExt_CreateObjectMenu.cs
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
using TMPro.EditorUtilities;
using UnityEditor;
using UnityEngine;
using UnityEngine.UI;
namespace Rainbow.UI
{
public static class UGUIExt_CreateObjectMenu
{
[MenuItem("GameObject/UI/ScaleButton - TextMeshPro", false, 2031)]
public static void AddButton(MenuCommand menuCommand)
{
TMPro_CreateObjectMenu.AddButton(menuCommand);

for (int i = 0; i < Selection.gameObjects.Length; i++)
{
string selectName = Selection.gameObjects[i].name;
if(selectName == "Button")
{
GameObject tg = Selection.gameObjects[i];
tg.name = "UIScaleButton";
GameObject.DestroyImmediate(tg.GetComponent<Button>());
tg.AddComponent<UIScaleButton>();
}
}
}

}
}

4.效果