找回密码
 立即注册
查看: 311|回复: 0

Unity中的ScrollRect滑动结束后,自动将最靠近中间的元素居中

[复制链接]
发表于 2022-4-27 14:22 | 显示全部楼层 |阅读模式
思路

在停止滑动(OnEndDrag)时,调整Content的localPosX:使其逐渐变为与其最接近的若干的标准PosX中的那个。
说明

当前只支持横向滑动。

2种模式:
    根据停止滑动时是左滑还是右滑来决定自动滑动方向当前哪个元素最靠近中央,就将该元素的位置归到中央
用法

将UIScrollRectAdjustor挂在ScrollRect同级节点上。

可配置
    自动移动时的移动速度使用哪种模式寻找标准PosX。
具体实现

UIScrollRectAdjustor.cs
using System.Collections;using System.Collections.Generic;using UnityEngine;using UnityEngine.UI;using UnityEngine.EventSystems;[RequireComponent(typeof(ScrollRect))]public class UIScrollRectAdjustor : MonoBehaviour, IEndDragHandler, IBeginDragHandler{    private ScrollRect _scrollRect;    private RectTransform _contentRectTrans;    private float _minX;    private float _baseX;    private float _xOffset;    [SerializeField,Header("自动移动时的移动速度")]    private float _moveSpeed = 3000;    private IEnumerator _autoMoveCoroutine;    [SerializeField, Header("方向优先")]    private bool _shouldBaseOnMoveDir;    private void Start()    {        Init();    }    private void OnDestroy()    {        Destroy();    }        public void Init()    {        _minX = 0;        _scrollRect = GetComponent<ScrollRect>();        _contentRectTrans = _scrollRect.content;        var gridLayoutGroup = _contentRectTrans.GetComponent<GridLayoutGroup>();        _baseX = gridLayoutGroup.cellSize.x / 2 + gridLayoutGroup.padding.left;        _xOffset = gridLayoutGroup.cellSize.x + gridLayoutGroup.spacing.x;    }        public void Destroy()    {        StopAutoMove();        _scrollRect = null;        _contentRectTrans = null;    }    public void OnBeginDrag(PointerEventData eventData)    {        if (_minX == 0)        {            var gridLayoutGroup = _contentRectTrans.GetComponent<GridLayoutGroup>();            _minX = _contentRectTrans.sizeDelta.x - gridLayoutGroup.padding.right - gridLayoutGroup.cellSize.x - gridLayoutGroup.spacing.x / 2;            _minX *= -1;        }        StopAutoMove();    }    private bool _isLeftMove;    public void OnEndDrag(PointerEventData eventData)    {        float curX = _contentRectTrans.localPosition.x;        if (curX < 0)        {            _isLeftMove = _scrollRect.velocity.x < 0;            float suitableX = GetSuitableX(curX);            StartAutoMove(curX, suitableX);        }    }    private float GetSuitableX(float curX)    {        float suitableX = curX;        int index = 0;        float leftX;        float rightX;        while (suitableX >= _minX)        {            leftX = GetX(index);            rightX = GetX(index + 1);            if (leftX >= curX && rightX <= curX)            {                var leftXOffset = Mathf.Abs(leftX - curX);                var rightXOffset = Mathf.Abs(rightX - curX);                if (_shouldBaseOnMoveDir)                {                    suitableX = _isLeftMove ? rightX : leftX;                }                else                {                    suitableX = leftXOffset < rightXOffset ? leftX : rightX;                }                break;            }            index++;        }        return Mathf.Max(suitableX, _minX);        float GetX(int i)        {            float value = 0;            if (i > 0)            {                value = (_baseX + _xOffset * i) * -1 + _baseX;            }            return value;        }    }        private void StartAutoMove(float beginX, float endX)    {        StopAutoMove();        _autoMoveCoroutine = AutoMoveCoroutine(beginX, endX);        StartCoroutine(_autoMoveCoroutine);    }    private void StopAutoMove()    {        if (_autoMoveCoroutine != null)        {            StopCoroutine(_autoMoveCoroutine);            _autoMoveCoroutine = null;        }    }    private IEnumerator AutoMoveCoroutine(float beginX, float endX)    {        float timer = 0f;        float moveTime = Mathf.Abs(beginX - endX) / _moveSpeed;        while (timer < moveTime)        {            _contentRectTrans.localPosition = new Vector3(Mathf.Lerp(beginX, endX, timer / moveTime),                                                          _contentRectTrans.localPosition.y,                                                          _contentRectTrans.localPosition.z);            timer += Time.deltaTime;            yield return null;        }        _contentRectTrans.localPosition = new Vector3(endX, _contentRectTrans.localPosition.y, _contentRectTrans.localPosition.z);        _scrollRect.StopMovement();    }}
懒得打字嘛,点击右侧快捷回复 【右侧内容,后台自定义】
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

小黑屋|手机版|Unity开发者联盟 ( 粤ICP备20003399号 )

GMT+8, 2024-9-22 13:40 , Processed in 0.109621 second(s), 25 queries .

Powered by Discuz! X3.5 Licensed

© 2001-2024 Discuz! Team.

快速回复 返回顶部 返回列表