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;
    }
}

改完之后的效果:

 

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

如果对您有帮助,请按下述操作:

点击文章下方

点击文章下方

点击文章下方

点击屏幕右下方

如果本文值得您分享,请点击文章下方

 

posted @ 2017-09-01 18:35  蓝闪  阅读(9268)  评论(0编辑  收藏  举报