以下内容是根据Unity 2020.1.01f版本进行编写的
UGUI源代码之Button—长按按钮
1、目的
长按按钮应该是很常见也很实用的一个功能了吧,今天我们就来实现这个功能
2、参考
本文参考Unity官方的UGUI源代码
Github地址:https://github.com/Unity-Technologies/uGUI
3、代码阅读
查看Button源代码(部分):
public class Button : Selectable, IPointerClickHandler, ISubmitHandler
{
[Serializable]
/// <summary>
/// Function definition for a button click event.
/// </summary>
public class ButtonClickedEvent : UnityEvent {}
// Event delegates triggered on click.
[FormerlySerializedAs("onClick")]
[SerializeField]
private ButtonClickedEvent m_OnClick = new ButtonClickedEvent();
protected Button()
{}
……
}
Button类中继承了Selectable类,增加的只有一个ButtonClickedEvent事件
跳转到Selectable类:
public virtual void OnPointerDown(PointerEventData eventData)
{
if (eventData.button != PointerEventData.InputButton.Left)
return;
// Selection tracking
if (IsInteractable() && navigation.mode != Navigation.Mode.None && EventSystem.current != null)
EventSystem.current.SetSelectedGameObject(gameObject, eventData);
isPointerDown = true;
EvaluateAndTransitionToSelectionState();
}
public virtual void OnPointerUp(PointerEventData eventData)
{
if (eventData.button != PointerEventData.InputButton.Left)
return;
isPointerDown = false;
EvaluateAndTransitionToSelectionState();
}
其中,有两个函数OnPointerDown和OnPointerUp,其在鼠标按下和抬起时触发,有这么两个可以override的函数就可以实现按钮长按功能了
4、准备修改UGUI源代码
请看这篇:UGUI源代码之修改源代码的前期准备
已经准备过的同学可以跳过
5、自定义实现长按按钮
这个长按按钮并不复杂,在这里我直接把整段代码复制过来:
using UnityEngine.EventSystems;
using UnityEngine.UI;
using static UnityEngine.UI.Button;
public class LongPressedButton : Selectable
{
public int frames = 120;
public ButtonClickedEvent onClick = new ButtonClickedEvent();
public ButtonClickedEvent onLongPressBegin = new ButtonClickedEvent();
public ButtonClickedEvent onLongPress = new ButtonClickedEvent();
public ButtonClickedEvent onLongPressEnd = new ButtonClickedEvent();
private int timer = 0;
private bool isDown = false;
private bool isLongPress = false;
private bool hasLongPressStart = false;
public override void OnPointerDown(PointerEventData eventData)
{
if (!isDown && !isLongPress)
{
isDown = true;
}
}
public override void OnPointerUp(PointerEventData eventData)
{
if(!isLongPress)
{
// Selection tracking
if (IsInteractable() && navigation.mode != Navigation.Mode.None && EventSystem.current != null)
EventSystem.current.SetSelectedGameObject(gameObject, eventData);
onClick.Invoke();
}
else
{
onLongPressEnd.Invoke();
}
isDown = false;
isLongPress = false;
hasLongPressStart = false;
timer = 0;
}
protected override void Start()
{
timer = 0;
isDown = false;
isLongPress = false;
hasLongPressStart = false;
}
void Update()
{
if(isDown)
{
timer++;
if(timer >= frames)
{
isLongPress = true;
if(!hasLongPressStart)
{
hasLongPressStart = true;
onLongPressBegin.Invoke();
}
onLongPress.Invoke();
}
}
}
}
frames是控制按钮需要长按多少帧才触发长按的属性
isDown判断是否按下按钮
isLongPress判断是否长按按钮,如果长按的帧数大于设置的帧数,则isLongPress属性为true
hasLongPressStart判断是否执行过一次的开始长按事件,执行过后此属性为false,控制一次长按事件中开始长按事件只触发一次
代码逻辑比较简单,就是增加了4个事件,分别对应点击、长按开始、正在长按、长按结束4个事件
OnPointerDown函数设置isDown为true,此时如果一直长按按钮,updata函数中timer会一直增加,当timer帧数大于设置的frames帧数时,设置isLongPress为true,并且通过invoke函数调用onLongPressBegin函数和onLongPress函数,其中,onLongPressBegin函数调用一次后就不会再调用
OnPointerUp函数接受鼠标抬起的动作,如果此时isLongPress为false,则执行OnClick函数,否则执行onLongPressEnd函数,并将属性再次初始化
6、最终效果
7、项目工程源代码
待补~~
大佬们找到问题欢迎拍砖~