Unity Scroll左右滑动UI自动居中

最近要实现一个左右滑动图片和文字居中显示的功能,其实也可以理解为Scroll添加了Layout组件让第一个就居中,然后让每个UI保持相同的间距,每一次在屏幕上的手指滑动,UI都是滑动了相同的距离。用下面的脚本替换原来的ScrollRect即可:

using DG.Tweening;
using DG.Tweening.Core;
using DG.Tweening.Plugins.Options;
using System;
using UnityEngine;
using UnityEngine.EventSystems;
using UnityEngine.UI;

public class SameDistanceScroll : ScrollRect
{
    public Action<int> endDragAction;

    private int _totalIndex = 10;
    private int _nowIndex = 0;
    private bool _isIndexChanged;
    private float _beginX, _endX, _beginNormalPos;
    private static TweenerCore<float, float, FloatOptions> tween;

    public void Init(int totalIndex, int nowIndex = 0)
    {
        _totalIndex = totalIndex;
        _nowIndex = nowIndex;
        DOTween.To(() => horizontalNormalizedPosition, (x) => horizontalNormalizedPosition = x, (float)_nowIndex / (_totalIndex - 1), 0);
    }

    public override void OnBeginDrag(PointerEventData eventData)
    {
        tween.Complete();
        base.OnBeginDrag(eventData);
        _beginX = eventData.position.x;
        _beginNormalPos = horizontalNormalizedPosition;
    }

    public override void OnEndDrag(PointerEventData eventData)
    {
        base.OnEndDrag(eventData);
        _isIndexChanged = false;
        _endX = eventData.position.x;
        var distance = _beginX - _endX;
        if ( Mathf.Abs(distance) > 100f)
        {
            if (horizontalNormalizedPosition - _beginNormalPos < 0f)
            {
                if (_nowIndex > 0)
                {
                    _nowIndex--;
                    _isIndexChanged = true;
                }     
            }
            else
            {
                if (_nowIndex < _totalIndex - 1)
                {
                    _nowIndex++;
                    _isIndexChanged = true;
                }
            }
        }
        
        _beginX = 0;
        _endX = 0;
        if (horizontal)
        {
            tween = DOTween.To(() => horizontalNormalizedPosition, (x) => horizontalNormalizedPosition = x, (float)_nowIndex / (_totalIndex - 1), 0.5f);
            tween.onComplete += () => {
            if (_isIndexChanged)
                endDragAction?.Invoke(_nowIndex);};
        }          
    }
}

  • 7
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
实现这个功能,你可以使用UnityScroll Rect组件。首先,需要将所有页面放在一个父物体下,然后将这个父物体添加到Scroll Rect组件的Content属性中。 然后,你需要在代码中监听Scroll Rect组件的滑动事件,当用户停止滑动时,计算出最近的页面,然后将Scroll Rect组件的位置自动滑动到该页面。 下面是一个简单的示例代码,你可以将其添加到Scroll Rect组件所在的GameObject上: ```csharp using UnityEngine; using UnityEngine.UI; using UnityEngine.EventSystems; public class SnapScroll : MonoBehaviour, IEndDragHandler { public float snapSpeed = 10f; // 滑动速度 public float snapThreshold = 0.1f; // 吸附阈值 public GameObject[] pages; // 所有页面 private ScrollRect scrollRect; private RectTransform contentRect; private Vector2[] pagePositions; void Start() { scrollRect = GetComponent<ScrollRect>(); contentRect = scrollRect.content; // 计算每个页面位置 int pageCount = pages.Length; pagePositions = new Vector2[pageCount]; for (int i = 0; i < pageCount; i++) { RectTransform pageRect = pages[i].GetComponent<RectTransform>(); pagePositions[i] = contentRect.anchoredPosition - pageRect.anchoredPosition; } } public void OnEndDrag(PointerEventData eventData) { // 计算滑动速度和方向 Vector2 velocity = scrollRect.velocity; float direction = (scrollRect.horizontal ? Mathf.Sign(velocity.x) : Mathf.Sign(velocity.y)); // 计算滑动结束后最近的页面 int nearestPageIndex = 0; float nearestPageDistance = float.MaxValue; Vector2 contentPosition = contentRect.anchoredPosition; for (int i = 0; i < pagePositions.Length; i++) { float distance = Vector2.Distance(contentPosition - pagePositions[i], Vector2.zero); if (distance < nearestPageDistance) { nearestPageDistance = distance; nearestPageIndex = i; } } // 如果滑动速度大于阈值,按照滑动方向选择页面 if (Mathf.Abs(velocity.magnitude) > snapThreshold) { nearestPageIndex += (int)direction; nearestPageIndex = Mathf.Clamp(nearestPageIndex, 0, pagePositions.Length - 1); } // 计算滑动结束后页面的位置 Vector2 targetPosition = -pagePositions[nearestPageIndex]; targetPosition.x = Mathf.Clamp(targetPosition.x, 0, contentRect.sizeDelta.x - scrollRect.viewport.sizeDelta.x); targetPosition.y = Mathf.Clamp(targetPosition.y, -contentRect.sizeDelta.y + scrollRect.viewport.sizeDelta.y, 0); // 滑动到最近的页面 Vector2 currentPosition = contentRect.anchoredPosition; StartCoroutine(SmoothSnap(currentPosition, targetPosition)); } IEnumerator SmoothSnap(Vector2 currentPosition, Vector2 targetPosition) { while (Vector2.Distance(currentPosition, targetPosition) > 1f) { currentPosition = Vector2.Lerp(currentPosition, targetPosition, snapSpeed * Time.deltaTime); contentRect.anchoredPosition = currentPosition; yield return null; } contentRect.anchoredPosition = targetPosition; } } ``` 在这个代码中,我们使用了OnEndDrag事件来监听滑动结束事件,然后计算出滑动速度和方向,以及最近的页面。最后,我们使用协程来平滑地滑动到最近的页面。 在使用这个代码之前,你需要将pages数组中的所有页面物体放在一个父物体下,并且将Scroll Rect组件的Content属性设置为该父物体。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值