在设计UI按钮图标时就会考虑可读性,但如果能在程序被使用时鼠标悬浮按钮上的文字提示会更加的人性化。今天这篇文章将由Unity开发者章晓冰,为大家分享如何在Unity中实现鼠标悬浮UI控件提示。

171102y9hfe0u9m51u57d5.jpg

实现原理

创建提示控件

控件命名为“TipText”,这个自定义控件主要有Image和Text控件组成。每次悬浮在UI控件中就激活它,并将其置于悬浮控件下作为子物体,悬浮退出又回到2DUICanvas下作为子物体。控制脚本如下:

[C#] 纯文本查看 复制代码using System.Collections; using System.Collections.Generic; using UnityEngine; using UnityEngine.UI; /// <summary> /// 鼠标悬浮显示文本 /// </summary> public class UI2DHoverOnShowTipText : MonoBehaviour { #region 公有 public static UI2DHoverOnShowTipText M_Instance { get { if(null==_instance) { _instance = FindObjectOfType<UI2DHoverOnShowTipText>(); } return _instance; } } #endregion #region 私有 private static UI2DHoverOnShowTipText _instance; [SerializeField] private GameObject subObj; private Image subObjImage; private Text subObjTipText; private bool isInitSucceed = false; private RectTransform curRectTransform; /// <summary> /// //单位字的宽度 /// </summary> private const float unitWidth = 80.0f / 5.0f; #endregion // Use this for initialization void Start () { } // Update is called once per frame void Update () { if (!isInitSucceed) return; } /// <summary> /// 显示文本 /// </summary> /// <param name=rectParent>文本的父组件</param> /// <param name=content>文本内容</param> /// <param name=vecOffset>偏移</param> public void Show(RectTransform rectParent, string content, Vector2 vecOffset) { if (!isInitSucceed) return; subObjTipText.text = content; float widt = unitWidth * subObjTipText.text.Length; float height = subObjImage.rectTransform.sizeDelta.y; subObjImage.rectTransform.sizeDelta = new Vector2(widt, height); curRectTransform.SetParent(rectParent); curRectTransform.localPosition = Vector3.zero; curRectTransform.localPosition += curRectTransform.up * vecOffset.y + curRectTransform.right * vecOffset.x; subObj.gameObject.SetActive(true); // Debug.Log(show); } /// <summary> /// 隐藏 /// </summary> public void Hide() { curRectTransform.SetParent(GlobControl.M_Instance.M_Canvas2DUI.transform); subObj.gameObject.SetActive(false); } /// <summary> /// 初始化 /// </summary> public void Init() { curRectTransform = GetComponent<RectTransform>(); subObj.gameObject.SetActive(false); subObjImage = subObj.GetComponentInChildren<Image>(); subObjTipText = subObj.GetComponentInChildren<Text>(); isInitSucceed = true; } }

需要提示的按钮的编辑控制

在上面内容中可以得知,添加控制脚本“UI2DImageBtnState”之后该按钮在Inspector面板上可以编辑第一个类型“Just Hover Image”。如下图所示:

171232ki51or7di47us5du.jpg

Just Hover Image:只控制Image按钮的背景图片的悬浮和退出状态;

Just Text:只有文字提示,不改变背景图片状态;

All:表示Just Hover Image和Just Text两个都可以控制;

悬 浮文本的偏移:相对当前Image控制的位置向“X”和“Y”方向的偏移。


控制上述这几个变量在编辑面板的状态,变量如下所示:

[C#] 纯文本查看 复制代码 /// <summary> /// 鼠标悬浮进入时候的贴图 /// </summary> [SerializeField] private Sprite hoverOnSprite; /// <summary> /// 鼠标悬浮退出时候的贴图 /// </summary> [SerializeField] private Sprite hoverExitSprite; /// <summary> /// 悬浮文本提示 /// </summary> [SerializeField] private string tipStrContent; [SerializeField] /// <summary> /// 悬浮按钮的偏移 /// </summary> private Vector2 tipPosOffsetVec; [SerializeField] private IMAGEBTNHOVER_SHOW_TYPE curShowType; 结构体: /// <summary> /// 图标悬浮显示 /// </summary> public enum IMAGEBTNHOVER_SHOW_TYPE { /// <summary> /// 仅仅显示图片 /// </summary> JustHoverImage = 0, /// <summary> /// 仅仅显示文字 /// </summary> JustText = 1, /// <summary> /// 显示全部 /// </summary> All = 2 }

这几个变量想要在面板上进行如图所示的操作需要在新建一个“Editor”文件夹,在此文件夹里创建ControlInspect脚本,代码如下:

[C#] 纯文本查看 复制代码using System.Collections; using System.Collections.Generic; using UnityEditor; using UnityEngine; [CustomEditor(typeof(UI2DImageBtnState))] [CanEditMultipleObjects] public class ControlInspect : Editor { /// <summary> /// 悬浮图片 /// </summary> SerializedProperty hoverOnSprite; SerializedProperty hoverExitSprite; /// <summary> /// 悬浮文字 /// </summary> SerializedProperty tipStrConent; SerializedProperty tipPosOffsetVec; SerializedProperty curShowType; void OnEnable() { // Setup the SerializedProperties. hoverOnSprite = serializedObject.FindProperty(hoverOnSprite); hoverExitSprite = serializedObject.FindProperty(hoverExitSprite); tipStrConent = serializedObject.FindProperty(tipStrContent); tipPosOffsetVec = serializedObject.FindProperty(tipPosOffsetVec); curShowType = serializedObject.FindProperty(curShowType); } public override void OnInspectorGUI() { serializedObject.Update(); GUILayout.Label(按钮图标状态管理); // Debug.Log(staticFlagMask); IMAGEBTNHOVER_SHOW_TYPE curShowTypeEnum =(IMAGEBTNHOVER_SHOW_TYPE)curShowType.enumValueIndex; curShowTypeEnum = (IMAGEBTNHOVER_SHOW_TYPE)EditorGUILayout.EnumPopup(类型, curShowTypeEnum); curShowType.enumValueIndex = (int)curShowTypeEnum; switch (curShowTypeEnum) { //显示图片 case IMAGEBTNHOVER_SHOW_TYPE.JustHoverImage: { EditorGUILayout.PropertyField(hoverOnSprite, new GUIContent(悬浮进入的图标)); EditorGUILayout.PropertyField(hoverExitSprite, new GUIContent(悬浮退出的图标)); // tipStrConent.ClearArray(); } break; case IMAGEBTNHOVER_SHOW_TYPE.JustText: { tipStrConent.stringValue = EditorGUILayout.TextField(提示的文字内容, tipStrConent.stringValue); tipPosOffsetVec.vector2Value = EditorGUILayout.Vector2Field(悬浮文本的偏移, tipPosOffsetVec.vector2Value); } break; case IMAGEBTNHOVER_SHOW_TYPE.All: { EditorGUILayout.PropertyField(hoverOnSprite, new GUIContent(悬浮进入的图标)); EditorGUILayout.PropertyField(hoverExitSprite, new GUIContent(悬浮退出的图标)); tipStrConent.stringValue = EditorGUILayout.TextField(提示的文字内容, tipStrConent.stringValue); tipPosOffsetVec.vector2Value = EditorGUILayout.Vector2Field(悬浮文本的偏移, tipPosOffsetVec.vector2Value); } break; } serializedObject.ApplyModifiedProperties(); } }

按钮控制

最终的控制在“UI2DImageBtnState”脚本里,代码如下:

[C#] 纯文本查看 复制代码using System; using System.Collections; using System.Collections.Generic; using UnityEngine; using UnityEngine.EventSystems; using UnityEngine.UI; /// <summary> /// 鼠标悬浮退出控制按钮图标的状态 /// 鼠标按下(无论左右键)除了LeftControl键都认为是退出悬浮状态 /// </summary> public class UI2DImageBtnState : MonoBehaviour { #region 属性 /// <summary> /// 鼠标是否悬浮在该物体上了 /// </summary> public bool M_IsHoverOn { get { return isHoverOn; } } /// <summary> /// 提示文字 /// </summary> public string M_TipStrContent { set { tipStrContent = value; } } #endregion #region 私有变量 private Image curImageBtn; /// <summary> /// 鼠标悬浮进入时候的贴图 /// </summary> [SerializeField] private Sprite hoverOnSprite; /// <summary> /// 鼠标悬浮退出时候的贴图 /// </summary> [SerializeField] private Sprite hoverExitSprite; /// <summary> /// 悬浮文本提示 /// </summary> [SerializeField] private string tipStrContent; [SerializeField] /// <summary> /// 悬浮按钮的偏移 /// </summary> private Vector2 tipPosOffsetVec; [SerializeField] private IMAGEBTNHOVER_SHOW_TYPE curShowType; private bool isHoverOn = false; #endregion // Use this for initialization void Start () { curImageBtn = GetComponent<Image>(); curImageBtn.sprite = hoverExitSprite; if (null==curImageBtn) { // Debug.Log(gameObject.name + 的Image 组件为空); // Debug.LogError(gameObject.name + 的Image 组件为空); } Add_UIHover_CallBack_Method(); } // Update is called once per frame void Update() { //鼠标按下的时候认为是退出状态 if (Input.GetKey(KeyCode.Mouse0) Input.GetKey(KeyCode.Mouse1)) { //除了leftAlt键盘之外 if (Input.GetKey(KeyCode.LeftControl)) { return; } mouse_Hover_Exit(null); } } /// <summary> /// 鼠标悬浮进入 /// </summary> /// <param name=pd></param> private void mouse_Hover_On(PointerEventData pd) { if (curShowType == IMAGEBTNHOVER_SHOW_TYPE.JustHoverImagecurShowType== IMAGEBTNHOVER_SHOW_TYPE.All) { if (null != curImageBtn null != hoverOnSprite) { curImageBtn.sprite = hoverOnSprite; } } if (curShowType == IMAGEBTNHOVER_SHOW_TYPE.JustText curShowType == IMAGEBTNHOVER_SHOW_TYPE.All) { if (null != tipPosOffsetVec null != tipStrContent) { UI2DHoverOnShowTipText.M_Instance.Show(GetComponent<RectTransform>(), tipStrContent, tipPosOffsetVec); } } isHoverOn = true; } /// <summary> /// 鼠标悬浮退出 /// </summary> /// <param name=pd></param> private void mouse_Hover_Exit(PointerEventData pd) { if (curShowType == IMAGEBTNHOVER_SHOW_TYPE.JustHoverImage curShowType == IMAGEBTNHOVER_SHOW_TYPE.All) { if (null != curImageBtn null != hoverOnSprite) { curImageBtn.sprite = hoverExitSprite; } } UI2DHoverOnShowTipText.M_Instance.Hide(); isHoverOn = false; // Debug.Log(HoverExit); } private void OnDisable() { isHoverOn = false; } private void Add_UIHover_CallBack_Method() { //添加鼠标悬浮事件 EventTrigger trigger = GetComponent<EventTrigger>(); if (null == trigger) { trigger =gameObject.AddComponent<EventTrigger>(); } EventTrigger.Entry hoverOnEntry = new EventTrigger.Entry(); //如果时鼠标悬浮进入 hoverOnEntry.eventID = EventTriggerType.PointerEnter; hoverOnEntry.callback.AddListener((data) => { mouse_Hover_On((PointerEventData)data); }); trigger.triggers.Add(hoverOnEntry); //鼠标悬浮退出 EventTrigger.Entry hoverExitentry = new EventTrigger.Entry(); //如果时鼠标悬浮进入 hoverExitentry.eventID = EventTriggerType.PointerExit; hoverExitentry.callback.AddListener((data) => { mouse_Hover_Exit((PointerEventData)data); }); trigger.triggers.Add(hoverExitentry); //鼠标悬浮退出 EventTrigger.Entry pressEntry = new EventTrigger.Entry(); //如果时鼠标悬浮进入 pressEntry.eventID = EventTriggerType.PointerDown; pressEntry.callback.AddListener(delegate { mouse_Press_Down(); }); trigger.triggers.Add(pressEntry); } private void mouse_Press_Down() { // Debug.Log(press); } /// <summary> /// 外部设置悬浮状态 /// </summary> /// <param name=isHover></param> public void Set_Hover_State(bool isHover) { isHoverOn = isHover; //图标状态 if (curShowType == IMAGEBTNHOVER_SHOW_TYPE.JustHoverImage curShowType == IMAGEBTNHOVER_SHOW_TYPE.All) { if (null != curImageBtn null != hoverOnSprite) { if (isHover) { curImageBtn.sprite = hoverOnSprite; } else { curImageBtn.sprite = hoverExitSprite; } } } //文本状态 if (curShowType == IMAGEBTNHOVER_SHOW_TYPE.JustText curShowType == IMAGEBTNHOVER_SHOW_TYPE.All) { if (null != tipPosOffsetVec null != tipStrContent) { if (isHover) { UI2DHoverOnShowTipText.M_Instance.Show(GetComponent<RectTransform>(), tipStrContent, tipPosOffsetVec); } } } } } /// <summary> /// 图标悬浮显示 /// </summary> public enum IMAGEBTNHOVER_SHOW_TYPE { /// <summary> /// 仅仅显示图片 /// </summary> JustHoverImage = 0, /// <summary> /// 仅仅显示文字 /// </summary> JustText = 1, /// <summary> /// 显示全部 /// </summary> All = 2 }

到这里这个自定义控件就大功告成了。如果大家有需要的话可以直接拿去使用,不过如果需要提示的Image层级不是很高的话,有可能会出现提示文字被遮挡的情况。

结语

今天分享的提示按钮控件操作简单、实用,可以帮助大家节省不少的开发时间。后面我们还将继续为大家分享更多Unity实用的工具在Unity官方中文社区(unitychina.cn),请保持关注!

游戏, Unity, 工具锐亚教育

锐亚教育 锐亚科技 unity unity教程