Unity UGUI Scroll View 核心:Content 锚点与尺寸设置详解
做 UGUI 开发这几年来Scroll View 应该是被问得最多的组件之一。很多朋友第一次接触 Unity 3D 里的 Scroll View都是直接往场景里一拖然后顺手就把图片、按钮、文本全部塞进 Scroll View 节点下面结果运行起来发现列表不滚动、内容被裁剪、滚动条拖不动甚至出现内容直接消失在屏幕外的情况。这些问题归根结底都指向同一个地方——Content 节点没设置对。Scroll View 本身只是一个壳真正决定内容如何排列、如何滚动、显示范围多大全靠 Content 这个子节点。它就像是一张放在放大镜下面的纸Scroll View 的视口是放大镜Content 是那张纸的定位和尺寸。纸短了滚不动纸放歪了显示不全纸和放大镜没对齐干脆什么都看不到。这篇文章我把我这些年调 Scroll View 的经验全部整理出来围绕 Content 的设置讲清楚原理、步骤和踩过的坑希望能帮你一次搞清楚这个组件。1. 先认清 Scroll View 的组件结构别再对着空节点发呆1.1 Scroll View 自带的那几个子节点到底干什么的在 Hierarchy 窗口里右键选择 UI - Scroll ViewUnity 会自动生成一个结构固定的节点树Scroll View ├── Viewport │ └── Content ├── Scrollbar Horizontal └── Scrollbar Vertical很多新手看到这堆节点就懵了不知道每个节点是干嘛的更不知道内容应该挂哪里。实际上这个结构分工很清晰Scroll View 节点本身挂着一个 Scroll Rect 组件它是整个滚动逻辑的核心驱动但它只负责计算和响应不直接显示内容。Viewport 是视口挂了一个 Rect Mask 2D 组件有的版本还会挂 Image它的作用是裁剪显示区域。只有在这个矩形范围内的内容才会被看到超出部分被隐藏。你可以把它理解成一个取景框。Content 是内容的实际容器你要生成的列表项、图片、文字等全部放到这个节点下面。Scroll Rect 通过记录 Content 的位置偏移来实现滚动效果。两个 Scrollbar水平/垂直滚动条是可选的它们显示当前滚动进度也可以反过来拖动控制滚动位置。这里面最容易犯的错就是把内容直接挂到 Scroll View 节点下而不是 Content 下面。一旦挂错ScrollRect 完全不知道要滚动哪个对象因为它的 Content 字段指向的是 Content 节点不是 Scroll View 自身。1.2 Content 的本质它不是普通 UI 节点而是“可伸缩的内容承载容器”Content 和普通 UI 节点的最大区别在于它的大小不是固定的而是由里面的内容决定的。竖直列表的 Content 高度应该等于所有子项高度之和加上间距横向列表的 Content 宽度应该等于所有子项宽度之和。当 Content 的尺寸超过 Viewport 的尺寸时ScrollRect 就知道“有东西可以滚了”滚动条也会按比例显示当前视口位置。这个“可伸缩”特性决定了 Content 的 RectTransform 参数不能沿用默认的拉伸模式。很多人用默认锚点创建了一个 Scroll View然后发现 Content 的宽度被 Viewport 锁死高度又不会自动变化内容一多就溢出屏幕根本滚不起来。原因就在于Content 的锚点、pivot、尺寸适配方式三者没有配合好。这里先记住一个关键结论竖直列表Content 的锚点放在顶部居中0.5, 1pivot 放在顶部0.5, 1高度交给 Content Size Fitter 动态计算横向列表则相反锚点放在左侧垂直居中0, 0.5pivot 放在左侧0, 0.5。后续章节我会逐一解释为什么。1.3 ScrollRect 组件上那几个引用字段的含义选中 Scroll View 节点Inspector 里可以看到 Scroll Rect 组件它有几个很关键的字段Content指定要滚动的目标必须拖入 Content 节点。Horizontal / Vertical勾选后表示允许在对应方向滚动。Movement Type滚动到边界时的行为方式有 Unrestricted无限制、Elastic弹性、Clamped夹紧三种。Horizontal Scrollbar / Vertical Scrollbar绑定对应的滚动条。Viewport指定视口引用一般会自动填好。排查 Scroll View 问题的时候第一步永远是检查 ScrollRect.Content 是否指向了正确的 Content 节点。我遇到过好几次用户说“列表不能滚”结果一看 Content 字段是空的Scroll Rect 根本不知道要滚动谁当然没反应。2. Content 的 RectTransform 核心参数锚点、pivot 与尺寸设置2.1 锚点决定 Content 以谁为参照物这是滚动的基石Anchor锚点是 UGUI 里最容易让新人困惑的概念但它对 Content 来说尤其重要。锚点本质上定义了当前节点的 RectTransform 相对于父节点Viewport的定位基准。Anchor Min 和 Anchor Max 共同决定了锚点区域的位置。以竖直列表为例Content 的父节点是 Viewport。如果把 Content 的锚点设置为左上角Anchor Min (0.5, 1)Anchor Max (0.5, 1)意味着 Content 的锚点位于 Viewport 的顶部水平居中位置。此时 Content 的 position、width、height 都是相对于这个锚点计算的位置从顶部开始向下延伸宽度默认取的是 Viewport 的宽度乘以某个比例高度由内容决定。一种常见的错误是把 Content 的锚点保持默认的拉伸模式Anchor Min (0, 0)Anchor Max (1, 1)。这种模式下 Content 的宽高会被强制拉伸到跟 Viewport 一样当你把内容高度撑大之后Content 的 RectTransform 会被拉伸模式锁死子项溢出但 Content 本身高度不变滚动范围永远不会扩大列表自然滚不动。所以设置 Content 的第一步就是改锚点竖直列表选 top-center顶部水平居中横向列表选 middle-left中部左侧。改锚点的时候要连同 pivot 一起改因为 UGUI 在设置锚点时会弹出一个选项问你是否同时修改 pivot 的位置这里建议勾选。2.2 pivot 影响的是“Content 从哪里开始向外扩展”Pivot轴心点是 RectTransform 的位置基准点。它取值在 (0,0) 到 (1,1) 之间(0,0) 代表左下角(1,1) 代表右上角(0.5, 0.5) 是中心点。Content 的位置、旋转、缩放都围绕 pivot 进行而 ScrollRect 的滚动偏移计算也跟 pivot 密切相关。竖直列表的 Content 为什么要设置 pivot 为 (0.5, 1)因为 pivot 在顶部那么 Content 的 position 表示的坐标点就在 Content 的顶端。当内容从顶部向下排列时pivot 固定在视口顶部向下的滚动就是 pivot 位置不变、Content 整体向上偏移视觉上表现为内容向上滚动。如果 pivot 在中心Content 的高度增加时它的中心点会被布局逻辑移动到……其实就乱了滚动范围不对内容有一半会跑到视口上方看不见。横向列表则要设置 pivot (0, 0.5)锚点在左边界垂直居中。这样 Content 从左侧开始向右延伸内容增多时向右扩展滚动时 pivot 固定在左侧边界不动。我给你的建议是把所有你自己创建的列表 Content 的 pivot 统一记成两个固定组合——竖直列表用 (0.5, 1)横向列表用 (0, 0.5)。别去试图理解每一种 pivot 的排列效果实际开发中这两种组合覆盖了绝大多数场景。2.3 sizeDelta 到底改的是宽高还是偏移一定要搞清楚RectTransform 里的 Width 和 Height 属性在 Unity 编辑器里看起来就是宽高但底层实际上改的是 sizeDelta。sizeDelta 的计算公式跟锚点有关当锚点是拉伸模式即锚点的 Min 和 Max 不在同一点时sizeDelta 表示的是节点相对于锚点区域的偏移量当锚点聚集在一个点上时sizeDelta 就直接等于节点的宽高。对 Content 来说锚点通常是一个点top-center 或 middle-left所以你在 Inspector 里修改 Width 和 Height 就是直接改尺寸。这有两个实际影响在 Content 没有挂 Content Size Fitter 组件时你必须手动保证 Content 的 Height 等于所有子项的总高度。如果你在脚本里动态生成 50 个条目每个高度 40 加上间距 5总高度就是 50 * 40 49 * 5 2245这里间距应该是 49 个而不是 50 个具体取决于你的间距设置方式通常布局组件会正确处理最后一个间距你需要把这个值赋值给 Content 的 RectTransform.sizeDelta.y。漏了这一步Content 高度永远是初始值后面生成的内容全部超出边界但滚动范围不增加。当你用代码读取 Content 的宽度时如果锚点是拉伸模式读出来的 width 可能是相对于锚点区域的偏移值不一定是真实像素宽度。所以凡是涉及 Content 尺寸计算的代码我建议先检查锚点设置是否满足“锚点为点”的前提。3. 配套组件配置Content Size Fitter 与 Layout Group 的正确打开方式3.1 Content Size Fitter 让 Content 自己撑开省去手动算高度手动计算 Content 高度在条目固定时可以接受但一旦列表变成动态数据每次增删条目都要重新计算高度和位置太容易出错了。Unity 提供了 Content Size Fitter 组件来自动完成这个工作。在 Content 节点上挂一个 Content Size Fitter 后Inspector 里有两个关键选项Horizontal Fit水平方向的适配模式默认 None。Vertical Fit垂直方向的适配模式默认 None。每个选项有四个取值None不处理、MinSize按子项最小尺寸适配、PreferredSize按子项首选尺寸适配、Unconstrained不约束尺寸按当前 RectTransform 的值。大多数情况下竖直列表设置 Horizontal Fit UnconstrainedVertical Fit PreferredSize横向列表反过来Horizontal Fit PreferredSizeVertical Fit Unconstrained。为什么不用 MinSize因为 MinSize 是子项约束计算出的最小尺寸而 PreferredSize 才是子项在正常情况下希望占据的尺寸。如果你的列表项设置了 Layout Element 组件PreferredSize 可以覆盖默认尺寸而 MinSize 不行。反过来如果你希望内容严格贴着子项的最小边界那才选 MinSize。常规列表使用 PreferredSize 是没问题的。需要注意Content Size Fitter 只负责修改 Content 的宽高它不会帮你排列子项的位置。子项排列需要配合 Layout Group两者通常一起使用。单独挂 Content Size Fitter 不挂布局组件的话子项还是用各自的 RectTransform 定位Content 的高度计算也会变得不可控因为布局信息缺失。3.2 Layout Group 选型竖直、横向、网格三种场景Content 下挂的布局组件主要有三种Vertical Layout Group垂直布局组子项从上到下排列适合聊天列表、排行榜、通知列表等。Horizontal Layout Group水平布局组子项从左到右排列适合横向滑动菜单、页签栏等。Grid Layout Group网格布局组子项按网格排列适合背包物品栏、商城商品展示等。实际开发中一个 Content 下有时会同时使用布局组配合不同大小的子项或者多个布局组嵌套外层横向内层竖直这些都有可能出现。以 Vertical Layout Group 为例常用参数有Padding内边距控制内容区与四边的间距。Spacing子项之间的间距。Child Alignment子项整体的对齐方式竖直列表通常用 Upper Center顶部水平居中或 Upper Left。Control Child Size勾选 Width / Height 后布局组件会强制控制子项的宽高。Use Child Scale是否把子项的 Scale 计入布局计算一般保持关闭。Child Force Expand如果勾选子项会被拉伸以填满剩余空间。对于固定高度的列表项这个选项通常要取消勾选否则每个条目会被平均拉伸视觉上怪怪的。我见过很多次列表显示不正常的场景排查到最后都是 Child Force Expand 被勾选了。这个选项的作用是让子项在主轴方向上尽量扩展以填满父容器的剩余空间。如果你做的是内容长度不固定、每个条目高度不同的列表勾了它之后所有条目都被拉伸成同样高度非常容易发现是这里的问题。3.3 用 Layout Element 控制每个子项的尺寸有时候子项自身的宽高并不来自 Image 或 Text 的原始尺寸而是需要手动指定。这时候就要在子项上挂 Layout Element 组件。Layout Element 上可以设置Ignore Layout勾选后该子项不参与布局计算适合做悬浮元素、装饰元素。Min Width / Min Height子项的最小宽高。Preferred Width / Preferred Height子项的首选宽高。Flexible Width / Flexible Height弹性宽高配合 Child Force Expand 使用。最常见的用法是在列表项的根节点上挂 Layout Element设置 Preferred Height 为一个固定值比如 100然后让布局组按照这个值排列。这样即使子项内部的 Image 和 Text 大小不固定列表的整体高度计算也不会乱。我之前做的一个排行榜列表每个条目的背景图高度是 120但内部文字有的两行有的三行如果不设置 Preferred HeightContent Size Fitter 算出来的高度会根据子项实际显示高度波动滚动条的精度会变得很怪异。给每个条目统一设置 Preferred Height 140 后布局计算立即稳定下来。4. ScrollRect 组件联动设置与滚动手感调优4.1 Content 与 ScrollRect 的关联检查这一步决定能不能滚ScrollRect 组件上的 Content 字段必须指向 Content 节点这看起来是显而易见的但在实际项目中经常出现几种情况场景里存在多个 Scroll View复制粘贴时引用的 Content 还是旧节点导致新列表滚的是旧列表的内容。内容挂到了 Scroll View 节点下但 Content 字段指向另一个空节点运行后什么反应都没有。代码运行时动态创建的 Content 没有在创建后重新给 ScrollRect 赋值。检查方法很简单选中 Scroll View 节点看 ScrollRect 的 Content 字段是不是你想要的那个 Content。如果为空直接把 Hierarchy 里的 Content 拖进去。如果是代码创建的 ScrollRect记得在赋值后调用一次scrollRect.Rebuild(CanvasUpdate.Prelayout)或者在下一次 LateUpdate 中生效否则立即操作可能出现一帧的延迟问题。4.2 Movement Type 三种模式的手感差异别傻傻分不清ScrollRect 的 Movement Type 有三个选项Unrestricted无限制模式Content 可以滚出视口边界很远松手后停在哪儿就是哪儿。适合做自由拖拽的画布或地图。Elastic弹性模式Content 滚到边界时会像橡皮筋一样被拉回来松手后弹回边界内。最常用的模式手感自然。Clamped夹紧模式Content 不会超出边界拖到边缘就停住不会有过冲。适合一些需要精确控制位置的场景比如页签横滑导航。其中 Elastic 有一个 Elasticity 参数值越小反弹越猛烈值越大越接近 Clamped。我一般设置 0.1 到 0.2 之间太大会感觉拖不动太小又感觉轻飘飘。这个参数没有绝对标准你要根据自己产品的调性去试但大多数 UI 交互里 0.1 或 0.3 都是合理的起点。4.3 Inertia惯性与 Deceleration Rate减速比Inertia 勾选后松手时列表会保持滑动的惯性和速度继续前进一段距离然后逐渐减速停止。Deceleration Rate 是减速系数取值为 0 到 1。值越接近 0减速越快手感越“紧”值越接近 1减速越慢滑动距离越远手感越“飘”。项目里做商城商品列表时我把 Deceleration Rate 设为 0.135Unity 文档中的默认值但实际试玩后发现这个值偏“快”滚很久都停不下来。我把惯性关了改用 Clamped 模式配合动画做指定的滚动效果手感立刻精准了很多。结论就是如果你的列表需要精确停在某个位置比如分页浏览建议关掉惯性如果是信息流浏览开惯性会更顺滑。4.4 滚动条绑定与联动机制Scrollbar 的绑定有两种方式在 ScrollRect 上直接把 Horizontal Scrollbar / Vertical Scrollbar 字段拖入对应的 Scrollbar 节点。让 Unity 自动生成新建 Scroll View 时默认已经生成了 Scrollbar只需要确认字段引用正确。滚动条的联动机制是Scrollbar 的 value 从 0 到 1表示滚动位置的百分比ScrollRect 在滚动时会调用 Scrollbar 的 SetValueWithoutNotify 更新进度反过来用户拖动滚动条时ScrollRect 会收到回调并更新 Content 的位置。因为存在双向联动调试时如果发现滚动条不动先检查是不是 Content 的滚动范围本来就是 0比如 Content 高度小于 Viewport 高度再检查 Scrollbar 的 Direction 是否与 ScrollRect 的滚动方向一致。4.5 滚动方向设置与别名的坑ScrollRect.Horizontal 和 Vertical 是两个独立开关理论上可以同时打开做出二维滚动效果比如大地图拖动。但如果你只是想要单向列表最好只开一个方向另一个关掉避免误触横向拖动。竖直列表把 Horizontal 勾选去掉同时把 Horizontal Scrollbar 清空否则 Content 宽度一旦超过 Viewport 宽度会莫名出现横向滚动条。这里有个常见的误区把 Scrollbar 的 Direction 设为 Bottom To Top 或 Left To Right很多人以为滚动条在右边就是从右到左滚动实际上 Direction 表示滚动条的增长方向不改变 Content 的滚动方向。Content 的滚动方向由 ScrollRect 的 Horizontal/Vertical 决定无法直接设置反向滚动要实现反向滚动需要自己控制 Content 的 anchoredPosition。5. 高频踩坑现场与排查套路5.1 Content 不滚动内容直接溢出屏幕外这是最常见的风格化问题症状是内容确实显示出来了但拖不动列表或者内容跑到了视口外面看不到。排查顺序我总结为四步看 ScrollRect 的 Content 字段是不是指向了正确的 Content 节点。看 Content 的锚点是否设置为 top-center 或 middle-left 这种“锚点为点”的模式不要用拉伸模式。看 Content 是否有足够大的尺寸。如果 Content 的高度刚好等于 Viewport 高度那自然没有滚动空间。你可以临时把 Content 的高度手动改大比如设为 1000看能不能滚如果能滚说明是尺寸适配的问题。看是否挂了 Content Size Fitter并且 Vertical Fit 是否设置为 PreferredSize。前面漏了这一步的话动态生成内容后高度不会更新列表永远不会滚。5.2 内容被裁剪掉一部分或者干脆看不见内容显示不全通常跟 Viewport 的裁剪范围有关但跟 Content 的设置也有关系。排查思路Viewport 上是否挂了 Rect Mask 2D 或 Mask 组件。如果 Viewport 没有遮挡组件它本身只是一个普通矩形是不会裁剪内容的内容会溢到列表外面。Content 的 pivot 是否在预期的位置。竖直列表如果 pivot 是 (0.5, 0.5)Content 以中心为基准扩展顶部可能会超出视野上方一部分看起来就像内容被切了。Content 的 Position 是否被误改。Content 偶尔会被拖拽到偏离视口的位置导致一部分内容在视口外面。此时把 Content 的 anchoredPosition 归零或按锚点正确设置即可恢复。5.3 内容撑开了但滚动条拖不动滚动条拖不动的原因一般是滚动条本身的 value 已经处于两端或者 Content 的实际尺寸并没有被内容撑开。举个典型场景你在 Content 里放了一张大图图超出了 Content 的高度但因为 Content 的 RectTransform 没有适配这只大图只是“溢出”显示Content 的高度依然是初始值滚动范围根本没变。解决办法是在 Content 上挂 Content Size Fitter并把对应的 Fit 设置为 PreferredSize或者用代码手动重新计算并赋值 Content 的高度。如果你用的是布局组件还需要确认布局组件在运行时的 Rebuild 已经完成布局计算要在 Content Size Fitter 更新之后、ScrollRect 更新之前生效。5.4 动态生成列表后 Content 高度没跟着变动态生成列表项后 Content 高度不更新基本可以断定是 Content Size Fitter 没有触发重算或者布局组件把子项的高度撑成了 0。生成列表项之后如果立刻去读 Content 的高度读到的可能还是上一帧的值。因为布局计算不是同步的RichText 和 LayoutGroup 的重算发生在 Canvas 的更新阶段。这时候可以手动强制重算LayoutRebuilder.ForceRebuildLayoutImmediate(contentRectTransform);这一行代码会同步执行一次布局重建执行完再读高度就是最新的。如果 Content 高度已经正确但滚动范围依然不对问题可能在 ScrollRect 的 content 引用或者 Viewport 的尺寸上。5.5 列表显示空白所有子项都不见了子项全都不见了先看 Content 的子节点是否都被禁用或者移到了 Content 外面再看布局组件的 Padding 是否设置了一个巨大的负数还要检查子项是否都被水平/垂直布局组件压缩成了 0 尺寸。一个非常隐蔽的坑是子项上挂了 LayoutElement 并且把 Preferred Height 设成了 0这时布局会把所有子项的高度全部压成 0列表显示空白但滚动范围还存在。排查这种问题我习惯把 Content 的 Debug 模式打开查看每个子项的 RectTransform 在运行时的实际宽高。如果全是 0问题出在布局计算如果尺寸正常但显示不出来问题出在 Canvas 渲染层级或 Mask 裁剪。5.6 Content 在编辑器正常运行后位置乱跳Editor 预览正常、运行后乱跳通常是因为脚本在 Awake/Start 里修改了 Content 的尺寸或位置然后又被布局系统在后续帧里改回来了。典型的写法是在 Start 里对 Content 的 sizeDelta 赋值然后计算滚动偏移。但是 Content Size Fitter 在下一帧又把 height 改回内容实际高度导致你设置的滚动偏移失效。我的建议是对带自动布局的 Content永远不要在脚本里直接设置它的 sizeDelta 来改变高度应该修改其子项或者修改布局参数。如果确实需要手动改 Content 尺寸就把 Content Size Fitter 禁掉或者用 VerticalLayoutGroup 的 padding 来控制高度。6. 性能优化别让 Content 背上几百上千个节点6.1 对象池 滚动复用别一次性生成所有条目当你需要显示 500 条甚至 1000 条数据时直接在 Content 下生成所有条目会导致 Canvas 重建成本巨大、点击命中检测变慢、Editor 卡顿明显。方案是对象池配合滚动复用只生成可视区域内需要的条目数量滚动过程中回收移出视口的条目放到对象池中再移动到新位置。具体逻辑可以这样写拿到 Content 的滚动位置计算当前视口覆盖的数据索引范围。遍历当前列表中已有的子项把索引不在可视范围内的子项回收SetActive(false) 并存入对象池。从对象池中取出或新建条目设置数据并摆放到对应的 anchor 位置。这个方案能极大减少节点数量但实现难度比一次性生成高。如果你的列表数据不超过 50 条我建议直接一次性生成不要过早优化数据量超过 200 条再考虑复用。6.2 动态生成时用代码控制 Layout 更新频率动态增删条目时布局组件会自动触发 Content 的重算。如果你在一帧内增删了几十个条目每次增删都会触发一次布局重建性能损耗非常大。更好的做法是先把所有条目对象放在 Content 下的一个临时节点里等全部设置完成后再一次性激活然后调用一次LayoutRebuilder.ForceRebuildLayoutImmediate把这一帧的布局重建合并成一次。6.3 Mask 裁剪与 Draw Call 的取舍Rect Mask 2D 本身会带来额外的渲染开销。Scroll View 的默认结构里Viewport 上的 Rect Mask 2D 是裁剪内容必需的但如果你不需要裁剪比如列表内容永不超出视口就不要挂 Mask省掉这份开销。另外被 Mask 裁剪的 UI 元素不会自动减少 DrawCall更不会减少顶点数。渲染管线依然会提交这些顶点只是最终显示时被裁剪掉。真正影响 UI 性能的是 Canvas 重建频率和顶点数量。所以如果你的列表项特别多建议避免在列表项里使用过于复杂的 UI 结构尽量用图集合并同类元素。6.4 大量图片列表的加载优化列表项里包含大量图片时不建议在创建时全部加载可以用一个懒加载方案只加载可视区域内条目的图片离开视口后立即释放计算量很小。配合对象池内存占用可以控制得非常低。我在某个模拟项目的商品流里就这么做过每页可视区只保留 10 个条目的贴图引用滚动时预加载前后各 3 个内存占用比一次性加载全部图片降低了 70% 以上。7. 代码动态创建 Content 的关键步骤有时候你需要在运行时动态创建一套 Scroll View 和 Content而不是用编辑器拖好的预制体。这里分享一下我常用的代码流程// 创建 ScrollView 根节点 GameObject scrollViewObj new GameObject(ScrollView, typeof(RectTransform), typeof(ScrollRect), typeof(Image)); scrollViewObj.transform.SetParent(canvasTransform, false); // 创建 Viewport GameObject viewportObj new GameObject(Viewport, typeof(RectTransform), typeof(RectMask2D), typeof(Image)); viewportObj.transform.SetParent(scrollViewObj.transform, false); RectTransform viewportRect viewportObj.GetComponentRectTransform(); viewportRect.anchorMin Vector2.zero; viewportRect.anchorMax Vector2.one; viewportRect.offsetMin Vector2.zero; viewportRect.offsetMax Vector2.zero; // 创建 Content GameObject contentObj new GameObject(Content, typeof(RectTransform)); contentObj.transform.SetParent(viewportObj.transform, false); RectTransform contentRect contentObj.GetComponentRectTransform(); contentRect.anchorMin new Vector2(0.5f, 1f); contentRect.anchorMax new Vector2(0.5f, 1f); contentRect.pivot new Vector2(0.5f, 1f); contentRect.sizeDelta new Vector2(400f, 800f); // 配置 ScrollRect ScrollRect sr scrollViewObj.GetComponentScrollRect(); sr.content contentRect; sr.viewport viewportRect; sr.horizontal false; sr.vertical true; sr.movementType ScrollRect.MovementType.Elastic; sr.inertia true;这串代码的关键点在于viewportRect 的锚点拉伸到填满 ScrollRectContent 的锚点和 pivot 设置在顶部。如果你的列表是动态高度别忘了在 Content 上挂 Content Size Fitter 和 Vertical Layout Group。代码创建 ScrollView 最常出的两个问题一是 Canvas 的 Render Mode 处于 Screen Space - Overlay 时RectTransform 的 parent 设置顺序可能导致位置错乱建议在 SetParent 之后再设置锚点和 sizeDelta二是不小心把 Content 建在了 ScrollView 节点下面而不是 Viewport 下面导致 Mask 裁剪失效。8. 调优总结与个人体会Scroll View 里 Content 的设置说到底是三个问题的组合锚点和 pivot 是否指定了正确的滚动基准Content 尺寸是否由内容自动撑开ScrollRect 的引用和滚动方向是否与 Content 匹配。这三个问题都解决了滚动列表基本就稳了。我自己在做一个跨平台列表功能时一开始也是直接拖默认的 Scroll View 用结果被“Content 高度固定”这个问题折腾了好几天。后来把所有列表项改成了由 Content Size Fitter 自动适配高度才发现问题根本不是数据问题而是布局层没配合好。以后凡是做列表我第一个动作就是检查 Content 的锚点、pivot 以及 Content Size Fitter 的三个值几百个小时的调试经验都浓缩在这几个参数里。最后分享一个小技巧如果你的列表滚动范围不对可以在运行时打开 Inspector 的 Debug 模式直接看 Content 的 RectTransform 数值同时把 ScrollRect 的 Movement Type 临时改成 Unrestricted拖一下看看 Content 会不会移出边界。这个办法能秒判断是“尺寸问题”还是“引用问题”比我当年一步步猜测效率高太多了。Scroll View 本身不难难的是把它的每个子组件都理解透。希望这篇文章能帮你少走弯路一次配置顺手。

相关新闻

点触验证码深度解析:从人机识别原理到工程接入与风控实践

点触验证码深度解析:从人机识别原理到工程接入与风控实践

1. 点触验证码到底在验证什么点触验证码这几年几乎遍布各类网站和App,从登录注册到下单支付,你可能每天都会碰到好几次。它的形态很直观:屏幕上出现一张图片,提示你“按顺序点击图中的文字”或者“点击包含某个物体的所有图片”&a…

2026/10/19 4:05:33 阅读更多 →
open-code-review:基于CLI+Git Diff+LLM Agent的开源代码评审实践

open-code-review:基于CLI+Git Diff+LLM Agent的开源代码评审实践

1. “open-code-review”不是新工具,而是一种正在重构代码协作范式的实践方法“open-code-review”这个词最近在开发者社区里高频出现,但它既不是某个开源项目的名字,也不是某家公司的商业产品代号。我第一次在 Slack 频道里看到它&#xff0…

2026/10/19 4:05:33 阅读更多 →
基于PyQt与深度学习的人脸识别课堂随机抽问系统设计

基于PyQt与深度学习的人脸识别课堂随机抽问系统设计

每年到毕业季,总有一批计算机专业的学生在选题阶段就卡壳。要说最稳妥的选择,还得是做一套“看得见、摸得着、能演示、能答辩”的系统。市面上常见的图书管理、商城秒杀早就烂大街了,答辩评委一眼就能看穿工作量。今天分享的这个项目——基于…

2026/10/19 4:05:33 阅读更多 →

最新新闻

代码审查自动化实践:open-code-review规则引擎与CI集成详解

代码审查自动化实践:open-code-review规则引擎与CI集成详解

1. 为什么我要折腾一个叫 open-code-review 的东西先交代一下背景。我一直在维护一个十几人的研发团队,代码审查这件事从我开始带队伍起就断断续续做过很多轮,但说实话效果一直不稳定。团队的 Code Review 流程一开始用的是最原始的方式:提 P…

2026/10/19 4:47:01 阅读更多 →
open-code-review:自动化代码评审与AI辅助实践指南

open-code-review:自动化代码评审与AI辅助实践指南

1. 先拆解需求:open-code-review到底解决什么问题做研发的同学都有体会,代码评审这件事,听着简单,做起来难受。难受在哪?不是不愿意看代码,而是没有好的机制和工具去支撑这个动作。你拉个群把代码链接丢进去…

2026/10/19 4:47:01 阅读更多 →
机器人建模中的隐式约定:DH参数、坐标系与逆解落地偏差解析

机器人建模中的隐式约定:DH参数、坐标系与逆解落地偏差解析

简介:本资源为经典教材《机器人建模与控制》(Mark W. Spong等著,Wiley 2006年出版)的完整课后习题答案解析,面向机器人学、自动化、控制工程等方向的本科生、研究生及科研人员,旨在辅助攻克运动学逆解、动力…

2026/10/19 4:47:01 阅读更多 →
从零构建代码评审系统:状态机驱动的评审闭环实践

从零构建代码评审系统:状态机驱动的评审闭环实践

1. 代码评审为什么值得单独做一个工具——行业现状与真实痛点1.1 评审不是挑刺,是质量闭环里最贵的一环先说个我观察到的现象:绝大多数团队讨论 code review,嘴上说的是"代码质量",实际做的却是"找茬"。大家把…

2026/10/19 4:47:01 阅读更多 →
自托管代码审查工具open-code-review的实践与落地

自托管代码审查工具open-code-review的实践与落地

代码审查这个环节,在很多团队里其实是“薛定谔的流程”——你说它有吧,每次合并请求(MR)确实都过了评审;你说它管用吧,线上事故的根因分析里,经常能看到“当时要是有人仔细看一眼”这种结论。我…

2026/10/19 4:47:01 阅读更多 →
open-code-review:基于规则引擎的增量代码评审实践指南

open-code-review:基于规则引擎的增量代码评审实践指南

代码评审这事儿,做久了你会有一个很直接的感觉:人眼靠不住。我自己在团队里评审过上千个 MR,也带过不少新同学参与评审,真正的问题从来不是“代码写得对不对”,而是“审查的人有没有在正确的时间看到正确的问题”。一次…

2026/10/19 4:46:01 阅读更多 →

日新闻

频率跟踪型PWM电源设计:臭氧发生器谐振点漂移与软开关实现

频率跟踪型PWM电源设计:臭氧发生器谐振点漂移与软开关实现

简介:本资源为电源技术方向的学术研究文档,聚焦介质阻挡放电型臭氧发生器电源的频率跟踪型PWM控制策略,面向电力电子、高压电源及臭氧应用领域的科研人员与工程技术人员。针对负载呈容性、等效电容随外加电压升高而增大、谐振频率随之漂移的难…

2026/10/19 0:00:47 阅读更多 →
Vibe Coding 遇上 TaoToken:把开发者思维圣殿的灵感流接入统一 Key 通道

Vibe Coding 遇上 TaoToken:把开发者思维圣殿的灵感流接入统一 Key 通道

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/19 0:00:47 阅读更多 →
HundredCV-Chat话题建模实战教程:利用4,871个内置话题标签构建主题分析系统

HundredCV-Chat话题建模实战教程:利用4,871个内置话题标签构建主题分析系统

【免费下载链接】HundredCV-Chat 项目地址: https://ai.gitcode.com/hf_mirrors/Jax-dan/HundredCV-Chat 点击查看 免费下载 HundredCV-Chat 是一个由 100 位青年简历数据开发而来的中文多轮对话数据集,共包含 24,750 组日常闲聊对话和 4,871 个话题标签…

2026/10/19 0:00:47 阅读更多 →

周新闻

基于GMM的语音识别系统原理与MATLAB实现详解

基于GMM的语音识别系统原理与MATLAB实现详解

说到基于高斯混合模型(GMM)的语音识别系统,很多人第一反应就是一堆数学公式,觉得门槛很高。但如果你真的在MATLAB里把它落地跑通,会发现核心其实就是三件事:把声音变成特征向量,用GMM给每个类别…

2026/10/18 0:00:55 阅读更多 →
数字图像处理入门:反白、灰度化、调色板修改与导出txt实践

数字图像处理入门:反白、灰度化、调色板修改与导出txt实践

数字图像处理这四个字听起来挺唬人,但落到具体操作上,无非就是让计算机按你的想法“摆弄”像素。我在一个模拟项目X里用了一套特别经典的基础处理流程:对图像做反白、改调色板、彩色转灰度,最后把像素数据导出成txt文件。单看每一…

2026/10/18 0:00:55 阅读更多 →
机器人大脑技术盘点:具身智能的感知、决策与数据闭环

机器人大脑技术盘点:具身智能的感知、决策与数据闭环

如果你的信息流最近也天天刷到“机器人大脑”这个词,你会发现一个很有意思的现象:每个人说的“大脑”根本不是同一个东西。有人指的是大语言模型,有人指的是运动控制系统,还有人指的是能理解物理世界的端到端模型。在2026年这个时…

2026/10/19 1:30:52 阅读更多 →

月新闻

我发现了一个新思路:用 Remotion + Claude Code 像写代码一样自动化生成短视频

我发现了一个新思路:用 Remotion + Claude Code 像写代码一样自动化生成短视频

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/19 2:54:50 阅读更多 →
Windows下 Codex 中 Chrome 和 Computer Use 插件不可用问题排查及解决参考方式:TaoToken 统一 Key 配置与验证

Windows下 Codex 中 Chrome 和 Computer Use 插件不可用问题排查及解决参考方式:TaoToken 统一 Key 配置与验证

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/17 17:22:31 阅读更多 →
黑夜航拍船只数据集训练YOLOV5模型全流程解析

黑夜航拍船只数据集训练YOLOV5模型全流程解析

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/18 12:16:16 阅读更多 →