Unity控件ScrollView使用問題記錄


Unity版本:5.6.2

控件Scroll View由4部分組成,如圖:

1.含有Scroll Rect組件的根節點:Scroll View

2.含有Mask組件的節點:Viewport

3.所有內容的父節點Content,常含有布局控件

4.滾動條,包括橫向和縱向

具體的節點細節使用可以參看官方文檔:
https://docs.unity3d.com/560/Documentation/Manual/script-ScrollRect.html

 

使用時遇到的問題記錄:

1.顯示區域怎么控制?
節點Scroll View中的組件Rect Transform的Width和Height控制着整個區域大小,組件Scroll Rect的滾動條設置也會影響顯示區域的邊界位置是否完整;

節點Viewport的組件Image中的Image Type屬性會影響顯示的區域;

節點Content的組件Rect Transform的布局和寬高影響了顯示的區域。

2.如何去掉滾動條?

節點Scroll View中的組件Scroll Rect中的屬性Horizontal Scrollbar和Vertical Scrollbar設置為None,並將其子節點Scrollbar Horizontal和Scrollbar Vertical刪除。

3.內容如何布局?

在節點Content中加入對應的布局組件即可。

4.出現無法滑動或者自動回彈到原地方的原因?

如果節點Content的寬度或者高度小於實際內容的寬度或者高度時,就會發生這樣的情況。這時需要調整Content的寬高,或者加入組件Content Size Fitter把對應方向設置為Preferred Size來自適應寬高。

5.滑動結束后,往往不能把當前的元素的畫面完整顯示的情況,如何解決?

這種情況需要給節點Scroll View掛載腳本來實現,腳本:ScrollRectCenterChild.cs代碼如下:

注意:Content節點的RectTransform組件中的Pivot屬性必須設置為0,1

Content節點的布局方式可以是Vertical Layout Group、Horizontal Layout Group 或者 Grid Layout Group,但都只支持一個方向的滑動居中。

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
using UnityEngine.EventSystems;
using System;

public enum ScrollDir
{
    Horizontal,
    Vertical
}


public class ScrollRectCenterChild : MonoBehaviour,IEndDragHandler,IDragHandler,IBeginDragHandler
{
    public ScrollDir Dir = ScrollDir.Vertical;
    private bool _isCentering = false;
    public float MoveToCenterSpeed = 10f;
    private ScrollRect _scrollView;
    private Transform _content;
    //用於保存子元素的坐標值
    private List<float> _childrenPos = new List<float>();
    private float _targetPos;
    private int _curCenterChildIndex = -1;

    public GameObject CurCenterChildItem
    {
        get
        {
            GameObject centerChild = null;
            if (_content != null && 0 <= _curCenterChildIndex && _curCenterChildIndex < _content.childCount)
            {
                centerChild = _content.GetChild(_curCenterChildIndex).gameObject;
            }
            return centerChild;
        }
    }

    private float GetChildItemWidth(int index)
    {
        return (_content.GetChild(index) as RectTransform).sizeDelta.x;
    }

    private float GetChildItemHeight(int index)
    {
        return (_content.GetChild(index) as RectTransform).sizeDelta.y;
    }

    void Awake()
    {
        _scrollView = GetComponent<ScrollRect>();
        if (null == _scrollView)
        {
            Debug.LogError("ScrollRect is null.");
            return;
        }
        _content = _scrollView.content;

        LayoutGroup layoutGroup = null;
        layoutGroup = _content.GetComponent<LayoutGroup>();
        if (null == layoutGroup)
        {
            Debug.LogError("LayoutGroup comment is null.");
            return;
        }

        float spacing = 0f;

        switch (Dir)
        {
            case ScrollDir.Horizontal:
                float scrollViewRectWidth = _scrollView.GetComponent<RectTransform>().rect.width;
                if (layoutGroup is HorizontalLayoutGroup)
                {
                    float childPosX = scrollViewRectWidth * 0.5f - GetChildItemWidth(0) * 0.5f;
                    _childrenPos.Add(childPosX);
                    spacing = (layoutGroup as HorizontalLayoutGroup).spacing;
                    for (int i = 1; i < _content.childCount; i++)
                    {
                        childPosX -= GetChildItemWidth(i) * 0.5f + GetChildItemWidth(i - 1) * 0.5f + spacing;
                        _childrenPos.Add(childPosX);
                    }
                }
                else if (layoutGroup is GridLayoutGroup)
                {
                    GridLayoutGroup grid = layoutGroup as GridLayoutGroup;
                    float childPosX = scrollViewRectWidth * 0.5f - grid.cellSize.x * 0.5f;
                    _childrenPos.Add(childPosX);
                    for (int i = 1; i < _content.childCount; i++)
                    {
                        childPosX -= grid.cellSize.x + grid.spacing.x;
                        _childrenPos.Add(childPosX);
                    }
                }
                else
                {
                    Debug.LogError("Horizontal ScrollView is using VerticalLayoutGroup.");
                }
                break;
            case ScrollDir.Vertical:
                float scrollViewRectHeight = _scrollView.GetComponent<RectTransform>().rect.height;
                if (layoutGroup is VerticalLayoutGroup)
                {
                    float childPosY = scrollViewRectHeight * 0.5f - GetChildItemHeight(0) * 0.5f;
                    _childrenPos.Add(childPosY);
                    spacing = (layoutGroup as VerticalLayoutGroup).spacing;
                    for (int i = 1; i < _content.childCount; i++)
                    {
                        childPosY += GetChildItemHeight(i) * 0.5f + GetChildItemHeight(i - 1) * 0.5f + spacing;
                        _childrenPos.Add(childPosY);
                    }

                }
                else if (layoutGroup is GridLayoutGroup)
                {
                    GridLayoutGroup grid = layoutGroup as GridLayoutGroup;
                    float childPosY = scrollViewRectHeight * 0.5f - grid.cellSize.y * 0.5f;
                    _childrenPos.Add(childPosY);
                    for (int i = 1; i < _content.childCount; i++)
                    {
                        childPosY += grid.cellSize.y + grid.spacing.y;
                        _childrenPos.Add(childPosY);
                    }
                }
                else
                {
                    Debug.LogError("Vertical ScrollView is using HorizontalLayoutGroup.");
                }
                break;
        }
    }

    void Update()
    {
        if (_isCentering)
        {
            Vector3 v = _content.localPosition;
            switch (Dir)
            {
                case ScrollDir.Horizontal:
                    v.x = Mathf.Lerp(_content.localPosition.x, _targetPos, MoveToCenterSpeed * Time.deltaTime);
                    _content.localPosition = v;
                    if (Math.Abs(_content.localPosition.x - _targetPos) < 0.01f)
                    {
                        _isCentering = false;
                    }
                    break;
                case ScrollDir.Vertical:
                    v.y = Mathf.Lerp(_content.localPosition.y, _targetPos, MoveToCenterSpeed * Time.deltaTime);
                    _content.localPosition = v;
                    if (Math.Abs(_content.localPosition.y - _targetPos) < 0.01f)
                    {
                        _isCentering = false;
                    }
                    break;
            }
        }
    }

    public void OnDrag(PointerEventData eventData)
    {
        
    }


    public void OnEndDrag(PointerEventData eventData)
    {
        switch (Dir)
        {
            case ScrollDir.Horizontal:
                _targetPos = FindClosestChildPos(_content.localPosition.x, out _curCenterChildIndex);
                break;
            case ScrollDir.Vertical:
                _targetPos = FindClosestChildPos(_content.localPosition.y, out _curCenterChildIndex);
                break;
        }
        _isCentering = true;
    }

    public void OnBeginDrag(PointerEventData eventData)
    {
        _isCentering = false;
        _curCenterChildIndex = -1;
    }

    private float FindClosestChildPos(float currentPos, out int curCenterChildIndex)
    {
        float closest = 0;
        float distance = Mathf.Infinity;
        curCenterChildIndex = -1;
        for (int i = 0; i < _childrenPos.Count; i++)
        {
            float p = _childrenPos[i];
            float d = Mathf.Abs(p - currentPos);
            if (d < distance)
            {
                distance = d;
                closest = p;
                curCenterChildIndex = i;
            }
        }
        return closest;
    }
}

改完之后的效果:

 

-------------------------------------------------------------------

如果對您有幫助,請按下述操作:

點擊文章下方

點擊文章下方

點擊文章下方

點擊屏幕右下方

如果本文值得您分享,請點擊文章下方

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM