官方把uGUI的源码公开有一段时间了,为了提高自己的代码设计、编写水平,就翻来看看吧,这次主要看看常用的Button组件的源码。
首先上类图,看看总体的设计。
UIBehavior及其派生类.png可以看到在uGUI系统中所有的UI组件都派生自抽象类UIBehavior,里面定义的抽象方法是每个Scene里的对象几乎都有的,如经常用到的Start(),Awake()等等。UIBehavior总共有14个派生类(图中没有显示),其中今天要看的Button被归为Selectable的子类,即“可选”的意思,而Image、Text、RawImage则被归为Graphic的抽象类(图中没有显示),写到这里我们已经可以看出编写者的设计思路了。
现在再看看Button的源码,第一次写文章,就讲细点吧。
using System;
using System.Collections;
using UnityEngine.Events;
using UnityEngine.EventSystems;
using UnityEngine.Serialization;
namespace UnityEngine.UI
{
// Button that's meant to work with mouse or touch-based devices.
[AddComponentMenu("UI/Button", 30)]
public class Button : Selectable, IPointerClickHandler, ISubmitHandler
{
[Serializable]
public class ButtonClickedEvent : UnityEvent {}
// Event delegates triggered on click.
[FormerlySerializedAs("onClick")]
[SerializeField]
private ButtonClickedEvent m_OnClick = new ButtonClickedEvent();
protected Button()
{}
public ButtonClickedEvent onClick
{
get { return m_OnClick; }
set { m_OnClick = value; }
}
private void Press()
{
if (!IsActive() || !IsInteractable())
return;
m_OnClick.Invoke();
}
// Trigger all registered callbacks.
public virtual void OnPointerClick(PointerEventData eventData)
{
if (eventData.button != PointerEventData.InputButton.Left)
return;
Press();
}
public virtual void OnSubmit(BaseEventData eventData)
{
Press();
// if we get set disabled during the press
// don't run the coroutine.
if (!IsActive() || !IsInteractable())
return;
DoStateTransition(SelectionState.Pressed, false);
StartCoroutine(OnFinishSubmit());
}
private IEnumerator OnFinishSubmit()
{
var fadeTime = colors.fadeDuration;
var elapsedTime = 0f;
while (elapsedTime < fadeTime)
{
elapsedTime += Time.unscaledDeltaTime;
yield return null;
}
DoStateTransition(currentSelectionState, false);
}
}
首先有一个为ButtonClickedEvent嵌套类型的m_OnClick字段,ButtonClickedEvent继承自UnityEvent,它是Unity的事件类。接下来看第一个私有方法Press(),这名字一看就知道是干嘛的了,方法里面也很简单,如果Button组件激活或者启用就调用m_OnClick的invoke方法,可为什么是私有的呢,这不方便调用啊?不急,继续往下看,OnPointerClick实现了IPointerClickHandler接口中定义的方法,方法内部进行了判断,仅左键按下时才调用Press方法。接下来OnSubmit也是类似的,但它实现的是ISubmitHandler接口的方法,按下提交按钮时(默认Enter)调用Press方法。
但老实说这里我一个地方没看懂,DoStateTransition和StartCoroutine是用来实现按钮触发的渐隐渐褪画面效果的,可OnPointerClick却没有,这是为什么?
好了,就先写到这里,虽然还有看不懂的地方,但思路和编写风格看懂了,平常工作中很少看得到接口和类的设计以及代码命名规范都做得很好的代码,也算有收获。下回再看看这个Button对应的Editor类,读懂了Editor也就知道官方是怎么写编辑器的了,虽然我之前也会写,但我觉得自己应该还可以写得更好一些。
网友评论