UGUI 布局与 SuperScrollView 列表实战
AI 摘要
解决Unity UI布局适配与动态交互痛点,涵盖RectTransform锚点计算、SuperScrollView列表刷新时序陷阱、LayoutGroup隐藏节点动效处理及进度条尺寸匹配策略,提供组件级细节优化方案。
UI 布局是「看起来简单、出错很频繁」的一块。这篇整理 RectTransform 基础、LayoutGroup 与动效的配合、SuperScrollView 的刷新顺序,以及若干组件级细节。
一、RectTransform 基础:锚点与四角
- 四个锚点的计算要熟练 —— 它决定了控件在不同分辨率下的拉伸与定位行为。
- 取世界坐标下的四角:
Vector3[] corners = new Vector3[4];
targetRectTransform.GetWorldCorners(corners);
// corners[0] 左下, corners[1] 左上, corners[2] 右上, corners[3] 右下
Image.SetNativeSize()可以把图片恢复为原始大小。
二、SuperScrollView 的四条经验
SuperScrollView(LoopListView2)在处理大量列表项时非常高效,但有几个反复踩的坑。
1. item 必须有 RectTransform 组件。
2. 切换数据时图片加载错误(例如背包切页签)
现象:切页签后 item 上的图片加载错乱。解法:用协程延迟刷新,等布局稳定后再刷新图片。
3. 不要直接 InitListView 后就完事
直接 InitListView 容易让 item 的动画失效。推荐顺序:
loopListView.InitListView(0, ItemRender); // 先传 0
loopListView.SetListItemCount(_enemyList.Count);
loopListView.RefreshAllShownItem();
4. SetListItemCount 与 RefreshAllShownItem 不要同时使用
前者本身就包含了「设置数量 + 刷新数量」的逻辑,两者叠加会重复刷新(必要时需要自己改内部实现)。
三、LayoutGroup 与「逐个入场」动效
LayoutGroup 默认不计算隐藏节点的布局。如果想给列表做「逐个淡入」的动效,有个可行的办法:
- 在 content 上挂
CanvasGroup,把alpha设为 0; - 等 item 都加载完(激活状态)后,
LayoutRebuilder.ForceRebuildLayoutImmediate(RectTransform)重新计算布局; - 遍历 content 依次失活所有 item;
- 禁用 LayoutGroup 和 ContentSizeFitter;
- 把
CanvasGroup.alpha设为 1; - 依次激活所有 item(期间可以做逐个出现的动效);
- 最后按需重新启用 LayoutGroup 和 ContentSizeFitter。
示例:
IEnumerator LoadChooseItem(params int[] param)
{
canvasGroup.alpha = 0;
MyFunction.DestroyAllChildren(chooseItemContent);
var list = GameplayManager.Instance.GetGameplayConfigIdList();
foreach (var gamePlayId in list)
{
var newChooseItem = Instantiate(chooseItem, chooseItemContent);
newChooseItem.gameObject.SetActive(true);
var playModeData = GameplayManager.Instance.GetPlayModeData(gamePlayId);
newChooseItem.SetData(playModeData);
if (param.Length > 0 && param[0] == gamePlayId)
{
isRedirected = true;
newChooseItem.OnClick();
}
}
LayoutRebuilder.ForceRebuildLayoutImmediate(chooseItemContent as RectTransform);
layoutGroup.enabled = false;
sizeFitter.enabled = false;
foreach (Transform trans in chooseItemContent)
trans.gameObject.SetActive(false);
canvasGroup.alpha = 1;
foreach (Transform trans in chooseItemContent)
{
trans.gameObject.SetActive(true);
yield return new WaitForSeconds(_actualItemShowInterval);
}
layoutGroup.enabled = true;
sizeFitter.enabled = true;
}
四、Toggle 的回调陷阱
使用 Toggle 时,不要在 onValueChanged 的回调里调用 ToggleGroup.ActiveToggles() —— 因为 toggle 的关闭和打开会分别调用该回调,可能导致 toggle 状态判断错误。
五、进度条:fillAmount 不匹配时怎么办
设置进度条时,如果原图与效果图的尺寸不匹配,用 fillAmount 会出现异常(填充区域对不上)。此时可以考虑用遮罩或 Shader 来实现。
六、DOTween 的 Ease 速查
DOTween 的 Ease 枚举里,常用缓动:
| 枚举 | 效果 |
|---|---|
Ease.OutQuad(值 6) |
先快后慢 |
Ease.InQuad |
先慢后快 |
Ease.InOutQuad |
两头慢、中间快 |
Ease.Linear |
匀速 |
七、指针事件接口
实现 IPointerDownHandler 等接口即可接收对应的指针事件(配合 Graphic Raycaster)。前提仍是目标的 Raycast Target 已开启。
小结
- 锚点决定适配行为,
GetWorldCorners四角顺序是「左下、左上、右上、右下」。 - SuperScrollView 记住三点:item 要有 RectTransform、刷新顺序是「先 0 → 设数量 → RefreshAllShownItem」、
SetListItemCount与RefreshAllShownItem不同时用。 - LayoutGroup 不算隐藏节点,配动效要走「先构建 → 全失活 → 逐个激活」的流程。
- Toggle 回调里别查 ActiveToggles;进度条尺寸不匹配就别硬用 fillAmount。
这是一条笔记,不是成稿文章。它可能不完整、可能有错,也可能过段时间就被我推翻。 想看成体系的文章,去 Blog。
linked from1 处引用了这篇