如何使用Unity UI滚动到ScrollRect中的特定元素?

Flo*_*rin 15 user-interface unity-game-engine unity3d-gui

我使用Unity 5.1为移动游戏构建了一个注册表单.为此,我使用Unity UI组件:ScrollRect + Autolayout(垂直布局)+文本(标签)+输入字段.这部分工作正常.

但是,打开键盘时,所选字段位于键盘下方.有没有办法以编程方式滚动表单以使选定的字段进入视图?

我尝试过使用ScrollRect.verticalNormalizedPosition它可以正常滚动一些,但是我无法将所选字段显示在我想要的位置.

谢谢你的帮助 !

mak*_*iuk 34

我将给你一个我的代码片段,因为我觉得有帮助.希望这可以帮助!

protected ScrollRect scrollRect;
protected RectTransform contentPanel;

public void SnapTo(RectTransform target)
    {
        Canvas.ForceUpdateCanvases();

        contentPanel.anchoredPosition =
            (Vector2)scrollRect.transform.InverseTransformPoint(contentPanel.position)
            - (Vector2)scrollRect.transform.InverseTransformPoint(target.position);
    }
Run Code Online (Sandbox Code Playgroud)

  • 我花了6个小时做这个,真的有这么简单吗?在forum.unity.com上浪费时间之前,我需要始终记得检查stackoverflow (3认同)
  • 谢谢。这就是解决方案。:-) (2认同)
  • 由于某些锚点,我不得不添加偏移量,否则这是一个很大的帮助/。 (2认同)

Pet*_*ris 8

没有任何建议对我有用,以下代码可以

这是扩展名

using UnityEngine;
using UnityEngine.UI;

namespace BlinkTalk
{
    public static class ScrollRectExtensions
    {
        public static Vector2 GetSnapToPositionToBringChildIntoView(this ScrollRect instance, RectTransform child)
        {
            Canvas.ForceUpdateCanvases();
            Vector2 viewportLocalPosition = instance.viewport.localPosition;
            Vector2 childLocalPosition   = child.localPosition;
            Vector2 result = new Vector2(
                0 - (viewportLocalPosition.x + childLocalPosition.x),
                0 - (viewportLocalPosition.y + childLocalPosition.y)
            );
            return result;
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

这就是我用它来滚动内容的直接子视图的方式

    private void Update()
    {
        MyScrollRect.content.localPosition = MyScrollRect.GetSnapToPositionToBringChildIntoView(someChild);
    }
Run Code Online (Sandbox Code Playgroud)


ved*_*anm 6

尽管@maksymiuk 的答案是最正确的答案,因为它正确地考虑了锚点、枢轴和所有其余部分,这要归功于 InverseTransformPoint() 函数,但它对我来说仍然无法开箱即用 - 对于垂直滚动条,它是也改变了它的 X 位置。因此,我只是进行了更改以检查是否启用了垂直或水平滚动,如果未启用,则不更改它们的轴。

public static void SnapTo( this ScrollRect scroller, RectTransform child )
{
    Canvas.ForceUpdateCanvases();

    var contentPos = (Vector2)scroller.transform.InverseTransformPoint( scroller.content.position );
    var childPos = (Vector2)scroller.transform.InverseTransformPoint( child.position );
    var endPos = contentPos - childPos;
    // If no horizontal scroll, then don't change contentPos.x
    if( !scroller.horizontal ) endPos.x = contentPos.x;
    // If no vertical scroll, then don't change contentPos.y
    if( !scroller.vertical ) endPos.y = contentPos.y;
    scroller.content.anchoredPosition = endPos;
}
Run Code Online (Sandbox Code Playgroud)

  • 欢迎来到 stackoverflow (4认同)
  • 有人可以指出我的答案有什么问题吗?它改进了已接受的答案,如果您的滚动只是水平或垂直,则该答案不起作用,我的改进适用于这些情况。 (2认同)
  • 请不要删除我的评论,你会让这个环境变得非常敌对。 (2认同)

v01*_*1pe 6

我的这个问题的版本的前提条件:

  • 我想要滚动到的位置element应该完全可见(间隙最小)
  • The是的 内容element的直接子级scrollRect
  • element如果已经完全可见,则保持滚动位置
  • 我只关心垂直尺寸

这对我来说最有效(感谢其他灵感):

// ScrollRect scrollRect;
// RectTransform element;
// Fully show `element` inside `scrollRect` with at least 25px clearance
scrollArea.EnsureVisibility(element, 25);
Run Code Online (Sandbox Code Playgroud)

使用此扩展方法:

public static void EnsureVisibility(this ScrollRect scrollRect, RectTransform child, float padding=0)
{
    Debug.Assert(child.parent == scrollRect.content,
        "EnsureVisibility assumes that 'child' is directly nested in the content of 'scrollRect'");

    float viewportHeight = scrollRect.viewport.rect.height;
    Vector2 scrollPosition = scrollRect.content.anchoredPosition;

    float elementTop = child.anchoredPosition.y;
    float elementBottom = elementTop - child.rect.height;

    float visibleContentTop = -scrollPosition.y - padding;
    float visibleContentBottom = -scrollPosition.y - viewportHeight + padding;

    float scrollDelta =
        elementTop > visibleContentTop ? visibleContentTop - elementTop :
        elementBottom < visibleContentBottom ? visibleContentBottom - elementBottom :
        0f;

    scrollPosition.y += scrollDelta;
    scrollRect.content.anchoredPosition = scrollPosition;
}
Run Code Online (Sandbox Code Playgroud)


小智 5

这是我将选定对象夹入 ScrollRect 的方式

private ScrollRect scrollRect;
private RectTransform contentPanel;

public void ScrollReposition(RectTransform obj)
{
    var objPosition = (Vector2)scrollRect.transform.InverseTransformPoint(obj.position);
    var scrollHeight = scrollRect.GetComponent<RectTransform>().rect.height;
    var objHeight = obj.rect.height;

    if (objPosition.y > scrollHeight / 2)
    {
        contentPanel.localPosition = new Vector2(contentPanel.localPosition.x,
            contentPanel.localPosition.y - objHeight - Padding.top);
    }

    if (objPosition.y < -scrollHeight / 2)
    {
        contentPanel.localPosition = new Vector2(contentPanel.localPosition.x,
contentPanel.localPosition.y + objHeight + Padding.bottom);
    }
}
Run Code Online (Sandbox Code Playgroud)