在内容大小拟合器更新内容的Rect转换后,如何使Unity Scroll Rect滚动到底部?

Kyl*_*ney 5 c# layout scroll scrollbar unity-game-engine

我有一个垂直滚动视图,我想动态添加内容。为此,我已将Content Size Fitter组件和Vertical Layout Group组件附加到Content游戏对象,以便每当我实例化新的游戏对象作为其子对象时,其Rect变换都会自动增长。如果滚动条已经在底部,那么在底部添加新对象后,我想将滚动条保持在底部。所以我这样做是这样的:

    if ( scrollRect.verticalNormalizedPosition == 0 )
    {
        isAtBottom = true ;
    }

    ScrollViewItem item = Instantiate( scrollViewItem, scrollRect.content ) ;

    if ( isAtBottom )
    {
        scrollRect.verticalNormalizedPosition = 0 ;
    }
Run Code Online (Sandbox Code Playgroud)

但是,这不起作用,因为新实例化的滚动视图项在我设置verticalNormalizedPosition为零时尚未增加Rect变换的大小。因此,当Rect Transform最终更新时,滚动到底部为时已晚。

举例来说,假设我的内容高度为400像素,滚动条一直位于底部。现在,我向其添加一个100像素高的对象。然后,我将滚动条发送到底部,但它仍然认为内容为400像素高。然后,内容大小将更新为500像素,但是滚动条向下缩小了400像素,因此它仅下降了80%,而不是100%。

有两种方法可以解决此问题。我想要一种方法来立即强制更新Content Size Fitter,或者作为一种事件来响应Content Size Fitter更新。

通过研究和实验,我将这些行按确切的顺序排列几乎成功了:

Canvas.ForceUpdateCanvases();
scrollRect.content.GetComponent<VerticalLayoutGroup>().CalculateLayoutInputVertical() ;
scrollRect.content.GetComponent<ContentSizeFitter>().SetLayoutVertical() ;
scrollRect.verticalNormalizedPosition = 0 ;
Run Code Online (Sandbox Code Playgroud)

但是,它并没有完全滚动到底部。始终相距约20像素。所以我想知道是否还有一些我不希望发生的布局操作。也许是填充之类的东西。

Wap*_*ull 8

没有Canvas.ForceUpdateCanvases 和疯狂迭代的正确方法。已确认在 Unity 中工作 2018.3.12

// Assumes
ScrollRect m_ScrollRect;
Run Code Online (Sandbox Code Playgroud)

在您更新 ScrollRect 内容并想要备份滚动条位置的地方

float backup = m_ScrollRect.verticalNormalizedPosition;

/* Content changed here */

StartCoroutine( ApplyScrollPosition( m_ScrollRect, backup ) );
Run Code Online (Sandbox Code Playgroud)

要应用新的滚动位置而不抖动,它需要在帧结束时,我们使用 Coroutine 等待该时间,然后使用LayoutRebuilder.ForceRebuildLayoutImmediate仅在该部分触发布局重建。

IEnumerator ApplyScrollPosition( ScrollRect sr, float verticalPos )
{
    yield return new WaitForEndOfFrame( );
    sr.verticalNormalizedPosition = verticalPos;
    LayoutRebuilder.ForceRebuildLayoutImmediate( (RectTransform)sr.transform );
}
Run Code Online (Sandbox Code Playgroud)

归功于:


小智 8

注册只是为了回答这个问题;我找到了一个更快的方法:

只需设置内容对象的锚点和枢轴(也可以有内容调整器组件),它就会从底部开始,然后向上滚动。

我的设置是:

  1. 从 Unity 中预设“滚动视图”并禁用滚动条
  2. “内容”对象具有垂直布局组件
  3. “content”对象具有内容适配组件
  4. “内容”对象的锚点设置为“底部拉伸”,同时也设置了锚点和枢轴

希望这对那些不想做自定义事情并且需要代码的人有所帮助,干杯


Kyl*_*ney 7

好吧,我相信我已经解决了。在大多数情况下,这Canvas.ForceUpdateCanvases();是设置verticalNormalizedPosition为零之前需要做的所有事情。但就我而言,我要添加到内容本身的项目还具有“垂直布局组”组件和“内容大小适合者”组件。所以我必须按以下顺序执行这些步骤:

Canvas.ForceUpdateCanvases();

item.GetComponent<VerticalLayoutGroup>().CalculateLayoutInputVertical() ;
item.GetComponent<ContentSizeFitter>().SetLayoutVertical() ;

scrollRect.content.GetComponent<VerticalLayoutGroup>().CalculateLayoutInputVertical() ;
scrollRect.content.GetComponent<ContentSizeFitter>().SetLayoutVertical() ;

scrollRect.verticalNormalizedPosition = 0 ;
Run Code Online (Sandbox Code Playgroud)

遗憾的是,关于这些方法的文档很少。

  • 谢谢!您的解决方案对我的情况也有效。在您的代码中, item 是滚动视图视口内的游戏对象“内容”;滚动矩形是滚动视图的滚动矩形。 (3认同)
  • @JohnStock-我认为如果您要投票否决我的想法,发布一个替代解决方案是一个好主意 (2认同)