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);
}
相关推荐
孟无岐3 小时前
【Laya】Ease 缓动函数
typescript·游戏引擎·游戏程序·laya
yi碗汤园4 小时前
【超详细】TCP编程与UDP编程
网络·网络协议·tcp/ip·unity·udp·visual studio
teunyu4 小时前
在Unity中使用LineRenderer实现A点到B点的贝塞尔曲线。并且曲线为虚线。方向为A点流向B点。效果图如下
unity·游戏引擎
速冻鱼Kiel4 小时前
GASP笔记03
笔记·ue5·游戏引擎·虚幻
nnsix4 小时前
Unity URP用于 光照贴图(Lightmap)的材质Shader
unity·材质·贴图
yi碗汤园4 小时前
【一文了解】网络请求
网络·unity
EucliwoodXT4 小时前
【Unity】项目部署Linux服务器
linux·unity·游戏引擎
微光守望者4 小时前
Unity小知识【2】:Transform与RectTransform,UI和3D对象的空间转换秘诀
ui·3d·unity
心之所向,自强不息4 小时前
URP的渲染流程
unity