前言
在学习凉鞋老师的课程《QFramework系统设计:通用背包系统》第五章时,笔者对物品提示TipPanel界面进行了一些优化。
优化内容包括:
- 解决闪烁问题
- 跟随鼠标移动
- 自适应界面大小
- 生成位置优化
效果还是蛮丝滑的:
解决闪烁问题
由于原代码逻辑是:当鼠标检测到Slot UI时,显示Tips;当未检测到Slot UI时,关闭Tips。
于是当Tips界面叠在Slot UI上时,鼠标移动到重叠部分便会反复触发以上逻辑。
此时只需要将Tips界面的Raycast Target关闭就可以了(如果需要Tips界面有交互,可以考虑其他解决方案)。
跟随鼠标移动
这个比较简单,就是将生成部分的代码封装成方法,在Update()方法中调用即可。
自适应页面大小
笔者给Tips界面添加了ContentSizeFitter组件,使其可以随自身内容改变大小。
但还是遇到一些问题,比如从一个Slot UI移动到另一个Slot UI上时,Tips界面的大小不会立即发生变化以适应新的大小。
原因是ContentSizeFitter的调整发生在布局的重计算阶段,在连续快速地更换内容时可能不会立即反映最新的内容变化。
这时候就需要使用LayoutRebuilder.ForceRebuildLayoutImmediate()方法,立即强制重建布局。
改为默认生成到鼠标的左下方
当鼠标靠近屏幕左边界时,生成到右下方;当鼠标靠近屏幕下边界时,生成到左上方;以此类推。
代码实现
csharp
using UnityEngine;
using UnityEngine.UI;
namespace QFramework
{
public class UIItemTip : MonoBehaviour
{
public GameObject TipPanel;
public Image Icon;
public Text NameText;
public Text DescriptionText;
public Text AttributeText;
public Text IDText;
private static UIItemTip mDefault;
private void Awake()
{
mDefault = this;
}
private void Start()
{
mDefault.TipPanel.Hide();
if (AttributeText.text == "")
AttributeText.Hide();
else
AttributeText.Show();
if (IDText.text == "")
IDText.Hide();
else
IDText.Show();
}
private void Update()
{
UpdatePosition();
}
public static void Show(UISlot slot)
{
if (slot.Data.Item != null)
{
mDefault.Icon.sprite = slot.Data.Item.GetIcon;
mDefault.NameText.text = slot.Data.Item.GetName;
mDefault.DescriptionText.text = slot.Data.Item.GetDescription;
mDefault.TipPanel.Show();
UpdatePosition();
}
}
public static void Hide()
{
mDefault.TipPanel.Hide();
}
public static void UpdatePosition()
{
Vector3 mousePos = Input.mousePosition;
Vector3[] corners = new Vector3[4];
RectTransform rectTrans = mDefault.TipPanel.transform as RectTransform;
// 更新TipPanel内容后,强制刷新布局
LayoutRebuilder.ForceRebuildLayoutImmediate(rectTrans);
// 获取界面的四个角点
rectTrans.GetWorldCorners(corners);
float width = corners[3].x - corners[0].x;
float height = corners[1].y - corners[0].y;
// 根据鼠标和屏幕的相对位置,调整生成 TipPanel 的位置
if (mousePos.y < height && mousePos.x > width)
rectTrans.position = mousePos + 0.5f * height * Vector3.up + 0.5f * width * Vector3.left;
else if (mousePos.y > height && mousePos.x < width)
rectTrans.position = mousePos + 0.5f * height * Vector3.down + 0.5f * width * Vector3.right;
else if (mousePos.y < height && mousePos.x < width)
rectTrans.position = mousePos + 0.5f * height * Vector3.up + 0.5f * width * Vector3.right;
else
rectTrans.position = mousePos + 0.5f * height * Vector3.down + 0.5f * width * Vector3.left;
// 0.51f 多了0.01f,使Tips和鼠标保持一小段距离
}
private void OnDestroy()
{
mDefault = null;
}
}
}