You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Unity中如何让ScrollView的Viewport始终居中?当前其偏左

问题:HorizontalScrollView Viewport无法自动居中(自定义ChiScrollRect脚本导致)
  • 当前HorizontalScrollView的Viewport默认处于左侧位置,手动拖动红色区域可将其大致居中,但需要实现自动保持居中的效果
  • 尝试按住Alt键选择锚点预设的Middle/Center,无法将Viewport设置为居中,问题根源在于挂载于HorizontalScrollView上的ChiScrollRect脚本(该脚本用于解决「鼠标在ScrollView内的按钮上时无法通过滚轮滚动」的问题)

效果截图

  • Viewport偏左状态:Viewport偏左
  • 目标居中效果:Viewport居中
  • Content对象设置:Content设置

自定义ChiScrollRect脚本代码

using UnityEngine;
using UnityEngine.EventSystems;
using UnityEngine.UI;

public class ChiScrollRect : ScrollRect, IPointerEnterHandler, IPointerExitHandler
{
    private static string mouseScrollWheelAxis = "Mouse ScrollWheel";
    private bool swallowMouseWheelScrolls = true;
    private bool isMouseOver = false;

    public void OnPointerEnter(PointerEventData eventData)
    {
        isMouseOver = true;
    }

    public void OnPointerExit(PointerEventData eventData)
    {
        isMouseOver = false;
    }

    private void Update()
    {
        // Detect the mouse wheel and generate a scroll. This fixes the issue where Unity will prevent our ScrollRect
        // from receiving any mouse wheel messages if the mouse is over a raycast target (such as a button).
        if (isMouseOver && IsMouseWheelRolling())
        {
            var delta = UnityEngine.Input.GetAxis(mouseScrollWheelAxis);

            PointerEventData pointerData = new PointerEventData(EventSystem.current);
            pointerData.scrollDelta = new Vector2(0f, delta);

            swallowMouseWheelScrolls = false;
            OnScroll(pointerData);
            swallowMouseWheelScrolls = true;
        }
    }

    public override void OnScroll(PointerEventData data)
    {
        if (IsMouseWheelRolling() && swallowMouseWheelScrolls)
        {
            // Eat the scroll so that we don't get a double scroll when the mouse is over an image
        }
        else
        {
            // Amplify the mousewheel so that it matches the scroll sensitivity.
            if (data.scrollDelta.y < -Mathf.Epsilon)
                data.scrollDelta = new Vector2(0f, -scrollSensitivity);
            else if (data.scrollDelta.y > Mathf.Epsilon)
                data.scrollDelta = new Vector2(0f, scrollSensitivity);

            base.OnScroll(data);
        }
    }

    private static bool IsMouseWheelRolling()
    {
        return UnityEngine.Input.GetAxis(mouseScrollWheelAxis) != 0;
    }
}

解决方案

1. 编辑器层面修正布局设置

  • Viewport设置:选择Viewport对象,在RectTransform面板中,按住Alt点击「Middle Center」预设,确保锚点(Anchor)和轴心(Pivot)均为(0.5, 0.5),位置(Position)设为(0, 0, 0),宽高与父级ScrollView保持一致
  • Content设置:
    • 如果使用Horizontal Layout Group组件,将「Child Alignment」设为Middle Center,确保内容在Content内垂直居中
    • 调整Content的RectTransform锚点:垂直方向设为(0, 0.5, 0, 0.5),保证Content始终在ScrollView垂直居中;水平方向锚点设为(0, 0.5, 0, 0.5)或(0,0,0,0)(根据需求选择)

2. 修改脚本添加初始化居中逻辑

在ChiScrollRect脚本中添加Start方法,初始化时自动将Content调整到居中位置,覆盖脚本可能导致的布局偏移:

private void Start()
{
    // 仅针对HorizontalScrollView处理居中
    if (!horizontal) return;

    float contentWidth = content.rect.width;
    float viewportWidth = viewport.rect.width;

    // 内容宽度大于视口时,计算居中偏移量;否则直接居中
    float targetPosX = contentWidth > viewportWidth ? -(contentWidth - viewportWidth) / 2f : 0f;
    content.anchoredPosition = new Vector2(targetPosX, content.anchoredPosition.y);
}

3. 修复脚本潜在的布局干扰

添加Reset方法,确保脚本重置时继承原生ScrollRect的默认属性,避免布局异常:

public override void Reset()
{
    base.Reset();
    // 重置为HorizontalScrollView的默认属性
    horizontal = true;
    vertical = false;
    movementType = MovementType.Elastic;
    elasticity = 0.1f;
}

内容的提问来源于stack exchange,提问作者Daniel Lip

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.23 18:13:08