Unity3d可配置UI动画

发表于2017-09-12
评论0 4.5k浏览

前言

这是我在项目中用来配置UI动画的View层组件,主要负责UI按钮的对应事件动画效果,以及各个窗口切换时的视觉表现,例如缩放,淡入淡出,回弹.这里面并没有涉及到项目的核心代码或商业机密,而且个人感觉很好用,所以将其独立出来,可以作为一个插件使用.代码我已经在GitHub上开源,希望对大家有所助益.下面将对整个UI动画配置组件进行复盘:

0x00 创建Unity项目

因为一开始就打算将UI动画组件独立出来成为插件,所以就从Unity编辑器上新建一个名为UiAnimationAgent的项目,路径大家可以选择在自己习惯的位置即可,如图1所示,点击Create project(创建项目)即可.

1 创建Unity项目

0x01 导入DoTween插件

因为这个UI动画系统是基于DoTween动画引擎来开发的,所以先导入该插件,方法是打开Unity编辑器的Asset Store资源商店,搜索DOTween插件名即可找到该插件,如图2所示,然后点击Download下载,点击Import导入,完成导入后会弹出设置菜单,点击Setup DOTween即可完成设置,关于DOTween的使用可以点击设置向导里面的Documentation来查看,网上也有不少关于DOTween的使用文章,这里就不再赘述.

2 DOTween插件

DOTween设置完成后,会自动弹出如图3窗口,点击Ok即可.

3 DOTween第三方库导入或更新

 

0x02 创建Main场景

Assets目录下新建Scene,ScriptsStreamingAssets文件夹,并在Scene文件夹下新建Main场景,然后双击打开Main场景,再在Main场景中新建一个按钮,并在该按钮上添加Main脚本,如图4所示,该脚本即是整个项目的入口,点击后即可进入游戏场景,这里Main对应你游戏的初始化场景即可,用来完成整个UiAnimationAgent的初始化.

4 创建Main场景

using UnityEngine;
using UnityEngine.SceneManagement;
using UnityEngine.UI;
namespace CLOUDHU.UIAnimationAgent {
	public class Main : MonoBehaviour {
		// Use this for initialization
		void Start() {
			//0.初始化DOTween动画组件
			DG.Tweening.DOTween.Init(true, true, DG.Tweening.LogBehaviour.ErrorsOnly).SetCapacity(200, 10);
			//1.读取Excel动画配置表
			CSVHelper.Instance().ReadCSVFile("uiAnimationConfig", (table) => {
				Debug.Log("读取动画配置表成功!");
			});
			//2.给按钮添加点击事件监听
			GetComponent

0x03 异步加载配置文件

上面Main脚本中,CSVHelper单例是用来加载动画的配置文件,这里借用了kashiwa同学的博客(Unity开发中异步加载配置文件,像读取数据库一样读取配置信息),非常的方便实用,这里就直接用了,详细的方法论大家不妨去kashiwa博客看看,这里不做重复解析.

使用时只需要在StreamingAssets文件夹下新建子文件夹GameConfig,然后把策划写好的Excel拖放进去即可.

策划大佬的配置表大致是这样的,如图5所示,打开UI动画配置文件uiAnimationConfig.csv,id表示UI动画唯一名称,这里把按钮和窗口大致分为大中小三种,每种类型又分为开始Start,End结束等阶段,不同阶段配置不同的time时间(以秒为单位),scale缩放,alpha透明度(淡入淡出的效果).

那么只需要在按钮和窗口(PanelCanvas)上面添加对应的UiAnimationAgent组件即可,在这些按钮或窗口初始化的时候就会配置对应idUI动画效果,当然,如果你觉得CSV不方便,还可以使用XML或者JSon来配置,只是解析时要改用对应的XML解析或LitJSon里面的JsonMapper.

5 uiAnimationConfig.csv动画配置文件 

0x04 按钮动画组件

按钮动画组件用于根据配置文件来控制每个按钮的对应事件动画:
// 
//  UiAnimationAgent
// 
// 胡良云(CloudHu)
//中文注释:胡良云(CloudHu) 7/10/2017
// --------------------------------------------------------------------------------------------------------------------
using DG.Tweening;
using UnityEngine;
using UnityEngine.UI;
namespace CLOUDHU.UIAnimationAgent {
	public enum eBtnAnimationType    //按钮类型枚举
{
		small,
		medium,
		big,
	};
	/// 
	/// FileName: BtnAnimation.cs
	/// Author: 胡良云(CloudHu)
	/// Corporation: 
	/// Description: 基于DOTween,按钮动画控制组件
	/// DateTime: 7/10/2017
	/// 
	public class BtnAnimation : MonoBehaviour {
		#region Public Variables  //公共变量区域
		[Tooltip("按钮大小类型")]
		public eBtnAnimationType btnType = eBtnAnimationType.small;
		[Tooltip("按下动画持续时间:秒")]
		public float timeDown = 0.1f;
		[Tooltip("按钮按下缩放比例")]
		public float scaleDown = 0.85f;
		[Tooltip("Alpha值")]
		public float alphaDown = 0.8f;
		public float timeDownStep1 = 0.1f;
		public float scaleDownStep1 = 1;
		public float alphaDownStep1 = 1;
		[Tooltip("松开动画持续时间:秒")]
		public float timeUp = 0.05f;
		[Tooltip("按钮松开缩放比例")]
		public float scaleUp = 1.2f;
		[Tooltip("Alpha值")]
		public float alphaUp = 1f;
		//[Tooltip("动画延迟多少秒后开始")]
		//public float delay = 0;
		[Tooltip("动画曲线类型")]
		public string easetype = "spring";
		public float timeUpStep1 = 0.1f;
		public float scaleUpStep1 = 1;
		public float alphaUpStep1 = 1;
		#endregion
		#region Private Variables   //私有变量区域
		bool m_bIfDownStep1 = false;//按下动画是否有额外步骤
		bool m_bIfUpStep1 = true;//松开动画是否有额外步骤
		Image m_imgComponent;//图片组件
		private bool m_gray = false;// 默认可用,变灰不可以再变色  
		//private bool m_init = false;
		Button m_BtnComponent;
		private enum eBtnEffectTpye {
			None,
			Light,
			Dark,
			Gray,
		}
		#endregion
		#region MonoBehaviour CallBacks //MonoBehaviour回调函数区域
		private void Awake() {
			m_imgComponent = transform.GetComponent();
			m_BtnComponent = transform.GetComponent

0x05 窗口动画组件

窗口动画组件用于按照配置文件来设置每个窗口的动画:
// 
//  UiAnimationAgent
// 
// 胡良云(CloudHu)
//中文注释:胡良云(CloudHu) 7/10/2017
// --------------------------------------------------------------------------------------------------------------------
using DG.Tweening;
using UnityEngine;
using UnityEngine.UI;
using System.Collections.Generic;
namespace CLOUDHU.UIAnimationAgent {
	/// 
	/// FileName: WindowAnimation.cs
	/// Author: 胡良云(CloudHu)
	/// Corporation: 
	/// Description: 基于DOTween,窗口动画控制组件
	/// DateTime: 7/10/2017
	/// 
	/// 
	public enum WindowAnimationType    //按钮类型
	{
		small,
		medium,
		big
	}
	public class WindowAnimation : MonoBehaviour {
		#region Public Variables  //公共变量区域
		float alphaInit = 0;
		float scaleInit = 0;
		[Tooltip("按钮大小类型")]
		public WindowAnimationType windowType = WindowAnimationType.small;
		[Tooltip("动画持续时间:秒")]
		public float timeOpen = 0.1f;
		[Tooltip("缩放比例")]
		public float scaleOpen = 0.95f;
		[Tooltip("Alpha值")]
		public float alphaOpen = 0.8f;
		public float timeOpenStep1 = 0;
		public float alphaOpenStep1 = 0;
		public float scaleOpenStep1 = 0;
		[Tooltip("松开动画持续时间:秒")]
		public float timeClose = 0.05f;
		[Tooltip("按钮松开缩放比例")]
		public float scaleClose = 1f;
		[Tooltip("Alpha值")]
		public float alphaClose = 1f;
		//[Tooltip("动画延迟多少秒后开始")]
		//public float delay = 0;
		[Tooltip("动画曲线类型")]
		public string easetype = "linear";
		//[Tooltip("动画循环类型")]
		//public iTween.LoopType looptype = iTween.LoopType.none;
		public float timeCloseStep1 = 0;
		public float alphaCloseStep1 = 0;
		public float scaleCloseStep1 = 0;
		public delegate void CloseWindowAnimationCallBack(GameObject callback);
		public Image m_imgBG = null;
		#endregion
		#region Private Variables   //私有变量区域
		bool m_bIfOpenStep1 = false;//按下动画是否有额外步骤
		bool m_bIfCloseStep1 = false;//松开动画是否有额外步骤
		bool m_IfInitFinished = false;  //是否完成动画配置初始化
		CloseWindowAnimationCallBack closeWindowAnimationCallBackTmp;
		CanvasGroup m_pcCavasGroup;
		float m_InitAlpha = float.NaN;
		#endregion
		#region MonoBehaviour CallBacks //MonoBehaviour回调函数区域
		// Use this for initialization
		void Awake() {
			m_pcCavasGroup = GetComponent();
			if (null == m_pcCavasGroup) {
				m_pcCavasGroup = gameObject.AddComponent();
			}
			if (m_imgBG == null) {
				m_imgBG = this.GetComponent();
				if (m_imgBG == null) {
					Image[] listImages = this.transform.GetComponentsInChildren();
					for (int i = 0; i < listImages.Length; i  ) {
						if (listImages[i].sprite != null && listImages[i].sprite.name.Contains("mengban")) {
							m_imgBG = listImages[i];
							break;
						}
					}
				}
			}
		}
		private void Start() {
			CSVTable table;//配置表
			table = CSVHelper.Instance().SelectFrom("uiAnimationConfig");
			if (null != table) {
				string prefix = "";//窗口大小前缀
				switch (windowType) {
					case WindowAnimationType.small:
						prefix = "small";
						break;
					case WindowAnimationType.medium:
						prefix = "medium";
						break;
					case WindowAnimationType.big:
						prefix = "big";
						break;
					default:
						break;
				}
				//Debug.Log(prefix   "WindowOpenStart");
				//初始化值
				alphaInit = float.Parse(table[prefix   "WindowOpenStart"]["alpha"]);
				scaleInit = float.Parse(table[prefix   "WindowOpenStart"]["scale"]);
				if (table.ContainsKey(prefix   "WindowOpenStep1")) {
					m_bIfOpenStep1 = true;
					timeOpen = float.Parse(table[prefix   "WindowOpenStep1"]["time"]);
					scaleOpen = float.Parse(table[prefix   "WindowOpenStep1"]["scale"]);
					alphaOpen = float.Parse(table[prefix   "WindowOpenStep1"]["alpha"]);
					alphaOpenStep1 = float.Parse(table[prefix   "WindowOpenEnd"]["alpha"]);
					timeOpenStep1 = float.Parse(table[prefix   "WindowOpenEnd"]["time"]);
					scaleOpenStep1 = float.Parse(table[prefix   "WindowOpenEnd"]["scale"]);
				}
				else {
					timeOpen = float.Parse(table[prefix   "WindowOpenEnd"]["time"]);
					scaleOpen = float.Parse(table[prefix   "WindowOpenEnd"]["scale"]);
					alphaOpen = float.Parse(table[prefix   "WindowOpenEnd"]["alpha"]);
				}
				if (table.ContainsKey(prefix   "WindowCloseStep1")) {
					//Debug.Log(table["smallWindowCloseStep1"]["time"]);
					m_bIfCloseStep1 = true;
					timeClose = float.Parse(table[prefix   "WindowCloseStep1"]["time"]);
					scaleClose = float.Parse(table[prefix   "WindowCloseStep1"]["scale"]);
					alphaClose = float.Parse(table[prefix   "WindowCloseStep1"]["alpha"]);
					alphaCloseStep1 = float.Parse(table[prefix   "WindowCloseEnd"]["alpha"]);
					timeCloseStep1 = float.Parse(table[prefix   "WindowCloseEnd"]["time"]);
					scaleCloseStep1 = float.Parse(table[prefix   "WindowCloseEnd"]["scale"]);
				}
				else {
					timeClose = float.Parse(table[prefix   "WindowCloseEnd"]["time"]);
					scaleClose = float.Parse(table[prefix   "WindowCloseEnd"]["scale"]);
					alphaClose = float.Parse(table[prefix   "WindowCloseEnd"]["alpha"]);
				}
				//Debug.Log(gameObject.name   "=>prefix:"  prefix   "  >>>  "   "timeOpen:"   timeOpen   "  scaleOpen:"   scaleOpen   "   alphaOpen:"   alphaOpen   "   alphaOpenStep1:"   alphaOpenStep1   "   timeOpenStep1: "   timeOpenStep1   "   timeOpenStep1"   timeOpenStep1   "   scaleOpenStep1:"   scaleOpenStep1   "   timeSinceLevelLoad: "   Time.timeSinceLevelLoad);
				m_IfInitFinished = true;
				OnWindowOpen();
				Debug.Log("读取动画配置表成功"   prefix);
			}
			table = null;
		}
		private void OnEnable() {
			if (m_imgBG != null) {
				if (float.IsNaN(m_InitAlpha)) {
					m_InitAlpha = m_imgBG.color.a;
				}
				Color _color = new Color(m_imgBG.color.r, m_imgBG.color.g, m_imgBG.color.b, m_InitAlpha);
				m_imgBG.color = _color;
			}
			if (m_IfInitFinished) {
				OnWindowOpen();
			}
		}
		#endregion
		#region Public Methods	//公共方法区域
		/// 
		/// 关闭窗口
		/// 
		public void OnWindowClose(CloseWindowAnimationCallBack windowAnimationCallBack) {
			if (!m_IfInitFinished) {
				//Debug.Log(m_IfInitFinished);
				windowAnimationCallBack.Invoke(gameObject);
				return;
			}
			if (m_imgBG != null) {
				Color _color = new Color(m_imgBG.color.r, m_imgBG.color.g, m_imgBG.color.b, 0);
				m_imgBG.color = _color;
			}
			if (m_bIfCloseStep1) {
				closeWindowAnimationCallBackTmp = windowAnimationCallBack;
				transform.DOScale(scaleClose, timeClose).OnComplete(OnCompleteClose);
			}
			m_pcCavasGroup.DOFade(alphaClose, timeClose);
			if (!m_bIfCloseStep1 && null != windowAnimationCallBack) {
				windowAnimationCallBack.Invoke(gameObject);
			}
		}
		#endregion
		#region Private Methods	//私有方法区域
		/// 
		/// 打开窗口
		/// 
		private void OnWindowOpen() {
			if (!m_IfInitFinished) {
				OnCompleteWindowAdjust();
				return;
			}
			m_pcCavasGroup.alpha = alphaInit;
			anchorAjust();
			transform.localScale = Vector3.one * scaleInit;
			if (m_bIfOpenStep1) {
				transform.DOScale(scaleOpen, timeOpen).OnComplete(OnCompleteWindowOpen);
			}
			else {
				transform.DOScale(scaleOpen, timeOpen).OnComplete(OnCompleteWindowAdjust);
			}
			m_pcCavasGroup.DOFade(alphaOpen, timeOpen);
		}
		/// 
		/// 窗口动画完成后进行自适应
		/// 
		void OnCompleteWindowAdjust() {
			anchorAjust();
		}
		void anchorAjust() {
			RectTransform rect = GetComponent();
			rect.offsetMin = Vector2.zero;
			rect.offsetMax = Vector2.zero;
		}
		void OnCompleteWindowOpen() {
			if (!m_IfInitFinished) {
				return;
			}
			transform.DOScale(scaleOpenStep1, timeOpenStep1).OnComplete(OnCompleteWindowAdjust);
			m_pcCavasGroup.DOFade(alphaOpenStep1, timeOpenStep1);
		}
		/// 
		/// 回弹效果
		/// 
		void OnCompleteClose() {
			if (!m_IfInitFinished) {
				return;
			}
			transform.DOScale(scaleCloseStep1, scaleCloseStep1).OnComplete(CloseWindowCallbackMethod);
			m_pcCavasGroup.DOFade(alphaCloseStep1, scaleCloseStep1);
		}
		/// 
		/// 关闭窗口回调
		/// 
		private void CloseWindowCallbackMethod() {
			if (null != closeWindowAnimationCallBackTmp) {
				closeWindowAnimationCallBackTmp.Invoke(gameObject);
			}
		}
		#endregion
	}
}

0x06 测试场景

最后是测试场景,新建名为Test的场景,将其添加到Build场景中,这样才能从Main场景加载过来,该场景主要用于测试按钮和窗口的动画,比较简单,这里就放一个脚本:
using CLOUDHU.UIAnimationAgent;//引用动画组件的命名空间
using UnityEngine;
using UnityEngine.UI;
/// 
/// 测试脚本
/// 
public class Test : MonoBehaviour {
	public GameObject m_widowPrefab;//窗口预设
	Button _btnOpen,_btnClose;//打开和关闭按钮
	// Use this for initialization
	void Start () {
		_btnOpen = transform.FindChild("BtnOpen").GetComponent

 最后,整个项目的代码在GitHub上开源:https://github.com/cloudhu/UiAnimationAgent

 有兴趣的朋友不妨点星Fork一下!其实利用DOTween还可以配置更多炫酷的UI动画效果,例如按钮抖动,窗口旋转等等,大家不妨对源码进行改进,如果有什么问题可以提Issue,谢谢!

PS:对VR感兴趣的朋友可以看看我的书,卡卡西老师也爱看的小黄书!

如社区发表内容存在侵权行为,您可以点击这里查看侵权投诉指引