项目中制作UI经常遇到的需求是:点击触控区域播放一段动画或者执行一些读取加载操作,如果动画未播放完或者读取操作正在进行,我们一般希望按钮短时间内不再响应触控。
解决这个问题的方法很多,这边简单罗列下:
1、最麻烦的方法:
每个按钮挂载一个脚本,执行touch方法的同时添加下次可以触控的逻辑条件,缺点:麻烦,写一堆赘余代码;
2、比较麻烦的方法:
按钮的On Click() 添加想要控制的Canvas组件,修改其Graphic Raycaster属性enable = false,或者创建canvas group,设置其Interactable或者Blocks Raycasts属性;
第二种方法优点设置简单方便,但是不灵活,如果CanvasA 遮挡CanvasB的同时,让CanvasB失去交互能力,但是如果想恢复CanvasB,可能需要借助另一个按钮或者额外添加脚本控制,相对于UI界面复杂的场景来说,还是很麻烦;
结合我之前做过cocos2d的游戏,我这边有一个想法是在点击按钮的同时(一般情况下点击按钮都是要执行脚本的),同时创建一个遮罩层来屏蔽场景中的所有Canvas的触控,这个遮罩层有一个自动销毁时间。比如说我点击按钮A的时候,需要执行一个2秒的过场动画,这段时间我不需要用户再点击按钮A,那我就可以在点击A的同时动态创建一个2秒后自动销毁的Mask,这样就不需要进行额外的控制,这个方法的好处就是适用所有的按钮,只要其他按钮调用这个方法就可以。
下面就是遮罩层的制作,遮罩层其实就是一个Canvas,它的Sort Order要足够大,打开它所有的射线碰撞属性同时添加一个Panel,保证它可以吞噬所有触控,再添加一个Canvas Group,把Alpha属性设为0(我们不希望看到Panel)。
将制作好的EmptyMask添加AutoDestroyMask脚本
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class AutoDestroyMask : MonoBehaviour {
/// <summary>
/// 遮罩层消失的时间
/// </summary>
public float _liveTime;
/// <summary>
/// 时间
/// </summary>
private float _timer;
// Update is called once per frame
void Update () {
_timer += Time.deltaTime;
if(_timer >= _liveTime){
Destroy(this.gameObject);
}
}
}
将它拖到Prefabs中制作预设体,将预设体放入路径:Resources/_Prefabs/EmptyMask/EmptyMask.profab, 编写工具类方法:
/// <summary>
/// 创建一个遮挡层
/// </summary>
public void __createEmptyMaskTouchCanvas(float __time){
string __prefabsPath = "_Prefabs/EmptyMask/EmptyMask";
GameObject __mask = (GameObject)MonoBehaviour.Instantiate(Resources.Load(__prefabsPath));
//设置销毁时间
__mask.GetComponent<AutoDestroyMask>()._liveTime = __time;
}
在需要短时间屏蔽触控的Button脚本中,把想控制按钮下次响应的时间作为参数调用这个方法即可。
总结:刚接触Unity项目不多久, 针对这个问题可能有其他更好的方法, 比如说使用DoozyUI插件,这里只是记录下我的解决思路,非常欢迎和期待熟手们提供其他更好的方法!