Button是Unity中最常用的组件之一。
来看下具体实现,继承自Selectable基类,并实现了IPointerClickHandler,ISubmitHandler接口。
先看看官方对于Selectable类的描述:
Simple selectable object - derived from to create a selectable control.
译:简单可选择对象-从派生以创建可选择控件。
这是在Inspector面板下的显示:
Selectable类及其子类在某一特定时刻都有相对应的状态。并且定义了状态的变化表现。
可以从Transition处选择表现类型:
当前使用的表现为颜色的变化,下面的分别是切换图片、触发动画。
Navigation项可以选择导航方式,可以通过上下左右键来切换当前选中的Selectable对象(前提是当前有选中对象)。
通过查看Selectable类的代码发现:
private static List<Selectable> s_List = new List<Selectable>();
里面定义了一个静态列表专门用来保存所有Selectable组件。每次切换时便从中取出正确的目标。
IPointerClickHandler接口应该是比较常用的,这里就不做赘述了。
ISubmitHandler接口里只定义了一个OnSubmit(BaseEventData eventData)方法。
当触发提交键的时候会调用当前选中物体的OnSubmit方法。
我们可以在Input设置中查看默认的提交键:
默认有两个,一个为enter,一个为return。
接下来看看Button类中具体做了些什么。
public class ButtonClickedEvent : UnityEvent {}
[FormerlySerializedAs("onClick")]
[SerializeField]
private ButtonClickedEvent m_OnClick = new ButtonClickedEvent();
protected Button(){}
public ButtonClickedEvent onClick
{
get { return m_OnClick; }
set { m_OnClick = value; }
}
首先,定义了一个继承自UnityEvent的ButtonClickEvent事件类。
UnityEvent里封装了Invoke,AddListener,RemoveListener等方法。
平时绑定移除监听就是在m_Onclick中进行的。
private void Press()
{
if (!IsActive() || !IsInteractable())
return;
UISystemProfilerApi.AddMarker("Button.onClick", this);
m_OnClick.Invoke();
}
public virtual void OnPointerClick(PointerEventData eventData)
{
if (eventData.button != PointerEventData.InputButton.Left)
return;
Press();
}
熟悉的OnPointerClick方法,仅当Left会触发Press()方法。
而Press中也限定了同时满足IsActive()和IsInteractable才会调用m_Onclick绑定的监听。
通过不断的追溯IsActive()最终定位到了isActiveAndEnabled这个字段。通过意思来推测Active和Enable均为true时才返回true。
这里我想提出一个疑问,为什么会有Active为true这个条件,难道这个Button即使Active为false时也能监听到点击?那么是不是可以大胆臆测一下其实Active为false的Button还在场景中原来的位置,只是没有渲染出来?那是不是所有GameObject都是这样处理的?这个问题等我以后来解决。
public virtual void OnSubmit(BaseEventData eventData)
{
Press();
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);
}
最后还有一个虚函数OnSubmit,我们发现这里也会调用Press()。
我们可以通过继承Button类重写OnSubmit方法来进行拓展。
但是多出来的状态转换和协程是做啥的,为什么OnPointerClick里没有?
还有什么情境下会用到这个东西?
等以后想到了到了再补充。