unity的背包滑动组件中道具的提示框被裁剪的问题

1.简单粗暴方法:

不使用最上层的canvas进行渲染,每个提示框单独挂载一个canvas渲染就可见了,不会被遮挡和裁剪了。

但为了"防止裁剪"而给每个道具都挂一个 Canvas,相当于"用大炮打蚊子"

问题:

每个道具都是一个独立的 Canvas。UI 系统需要为每一个 进行独立的布局计算、网格重建和批处理准备,无论其是否激活。这会产生大量固定的 CPU 开销 (管理 Canvas)和潜在的 GPU 开销(大量不可合并的小批次),在背包打开、滚动时会造成卡顿。

2.单一顶层Canvas:

  • 造成这个问题的核心原因是每个道具item都有自己的子对象,提示框。
  • 再滑动列表中会受到影响。
  • 那我们就将提示框移出Viewport的遮挡节点。
  • 那现在需要解决的问题就是控制提示框的位置定位,和显示隐藏
思路:
  1. 结构解耦

    • 将提示框预制体从所有道具项中彻底移除

    • UI顶层 (例如与背包面板同级,可以更具需要移动)创建一个唯一的、共享的提示框GameObject。它就挂在一个公共的、高级别的 Canvas 下。

  2. 事件驱动控制

    • 编写一个单例或管理器(如 TooltipManager),专门控制这个唯一的提示框。

    • 在每个道具的脚本上,继续处理鼠标悬停(OnPointerEnter)和离开(OnPointerExit)事件。

    • 鼠标悬停时 ,道具脚本不自己创建提示框 ,而是向 TooltipManager 发送请求:"请显示提示框,内容是我,我的位置是这里"。

    • TooltipManager 收到请求后,立刻隐藏当前可能正在显示的提示框,然后用新数据和位置更新那个唯一的提示框实例,再显示它。

    • 鼠标离开时,道具脚本通知管理器"隐藏提示框"。管理器可以加一个延时隐藏或判断鼠标是否已移到提示框本身上。

这个交互事件就不多说了,可以更具自己的需求实现,不管是点击,滑动还是鼠标悬停等。

简单列举几个接口,滑动,点击的,实现后挂载在ScrollRect上就可以,不能挂载到其子对象上,这些事件是不被ScrollRect继续向下传递的。

cs 复制代码
public class EventHandler : MonoBehaviourAutoRelease, IPointerUpHandler, IPointerDownHandler, IPointerClickHandler, IBeginDragHandler, IDragHandler, IEndDragHandler
{
    public Action<PointerEventData> OnBeginDragAction;

    public Action<PointerEventData> OnDragAction;

    public Action<PointerEventData> OnEndDragAction;

    public Action<PointerEventData> OnPointerClickAction;

    public Action<PointerEventData> OnPointerDownAction;

    public Action<PointerEventData> OnPointerUpAction;



    public void OnBeginDrag(PointerEventData eventData)
    {
        OnBeginDragAction?.Invoke(eventData);
    }

    public void OnDrag(PointerEventData eventData)
    {
        OnDragAction?.Invoke(eventData);        
    }

    public void OnEndDrag(PointerEventData eventData)
    {
        OnEndDragAction?.Invoke(eventData);
    }

    public void OnPointerClick(PointerEventData eventData)
    {
        OnPointerClickAction?.Invoke(eventData);
    }

    public void OnPointerDown(PointerEventData eventData)
    {
        OnPointerDownAction?.Invoke(eventData);
    }

    public void OnPointerUp(PointerEventData eventData)
    {
        OnPointerUpAction?.Invoke(eventData);
    }
}

列举下定位的问题把

  • AdjustTooltipPosition的内容就根据自己的需要去修改了

  • 位置实现的更具item相对于viewport的本地坐标的判断,修改了提示框背景板的朝向和位置效果如下图:

  • 其中使用到一个重要的API:InverseTransformPoint,将对象的世界坐标转换为相对目标的本地坐标的方法。其锚点是(0.5,0.5)

  • 因为我是将提示框放在,backpackScrollRect滚动组件下,所以转换的本地坐标可以直接赋值给提示框,实现定位。

cs 复制代码
[Header("背包引用")]
public ScrollRect backpackScrollRect;
public RectTransform viewportRect;
public RectTransform contentRect;



public RectTransform ItemTipObj;    // 提示框

    

public void ShowTooltip()
{
    RectTransform itemRect = transform.GetComponent<RectTransform>();
    if (itemRect == null) return;

    Vector2 itemInViewportLocalPos = backpackScrollRect.GetComponent<RectTransform>().InverseTransformPoint(itemRect.position);
    float viewportHalfWidth = backpackScrollRect.GetComponent<RectTransform>().rect.width / 2; 
    float itemRelativeX = Mathf.InverseLerp(-viewportHalfWidth, viewportHalfWidth, itemInViewportLocalPos.x + itemRect.rect.width / 2);
    itemRelativeX = Mathf.Clamp01(itemRelativeX);

    bool isLeftEdge = itemRelativeX < 0.5; 
    bool isRightEdge = itemRelativeX > 0.5; 

    
    AdjustTooltipPosition(itemRect, isLeftEdge, isRightEdge);
}


public void AdjustTooltipPosition(RectTransform itemRect, bool isLeft, bool isRight)
{
    Vector2 itemInViewportLocalPos = backpackScrollRect.GetComponent<RectTransform>()
        .InverseTransformPoint(itemRect.position);

    float pos = 0;
    if (isLeft) pos = 80;
    else pos = -80;

    ItemTipObj.localPosition = new Vector3(itemInViewportLocalPos.x + pos, itemInViewportLocalPos.y + itemRect.rect.height, 0);
    ItemTipObj.Find("Bg_RectTransform").transform.localScale = new Vector3(isLeft ? 1 : -1, 1, 1);
}
相关推荐
天人合一peng1 小时前
unity 通过代码修改button及其名字字体的属性
unity·游戏引擎
GLDbalala5 小时前
Unity基于自定义管线实现经典经验光照模型
unity·游戏引擎
心疼你的一切8 小时前
Unity异步编程神器:Unitask库深度解析(功能+实战案例+API全指南)
深度学习·unity·c#·游戏引擎·unitask
呆呆敲代码的小Y10 小时前
【Unity 实用工具篇】 | Book Page Curl 快速实现翻书效果
游戏·unity·游戏引擎·u3d·免费游戏·翻书插件
AC梦1 天前
unity中如何将UI上的字高清显示
ui·unity
小贺儿开发1 天前
Unity3D 智慧城市管理平台
数据库·人工智能·unity·智慧城市·数据可视化
June bug2 天前
【领域知识】休闲游戏一次发版全流程:Google Play + Apple App Store
unity
星夜泊客2 天前
C# 基础:为什么类可以在静态方法中创建自己的实例?
开发语言·经验分享·笔记·unity·c#·游戏引擎
dzj20212 天前
PointerEnter、PointerExit、PointerDown、PointerUp——鼠标点击物体,则开始旋转,鼠标离开或者松开物体,则停止旋转
unity·pointerdown·pointerup
心前阳光2 天前
Unity 模拟父子关系
android·unity·游戏引擎