unity UGUI无限循环滚动居中

最近在做一个ui循环滚动的功能,网上找了半天脚本感觉都和我实际需求不太符合,自己花费一些时间完成了这个功能记录一下。下面开始正题
我是采用unity自带组件Scroll View来完成,首先设置Scroll View如下图
首先是竖形循环
这个是
在这里插入图片描述
把这两个必备物体放进去,中心点创建一个空物体即可
在这里插入图片描述
这个地方按照顺序添加item 就可以

在这里插入图片描述

如何是横向的循环列表只需要修改脚本的枚举类即可 其他设置一样,如下图

在这里插入图片描述

然后开始编写代码,我就直接贴了,不懂可以看一下注释。

using DG.Tweening;
using QFramework;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.EventSystems;
using UnityEngine.UI;

public enum HVType
{
    Vertical,
    Horizontal
}
public class LoopScroll : MonoBehaviour, IBeginDragHandler, IEndDragHandler, IDragHandler
{
    public HVType tempHVType;

    Vector2 StartPos;
    [Header("中心点")]
    public Transform Centre;
    [Header("UI父级")]
    public Transform Content;
    [Header("间隔距离")]
    public float SpacingDistance = 100;
    [Header("缩放倍数")]
    public float Scale = 1;
    [Header("居中吸附速度")]
    public float Speed = 10;
    [Header("当前居中物体名称")]
    public Text tempCentreName;
    [Header("左右切换按钮")]
    public Button Left, Right;
    [Header("居中后UI缩放系数")]
    public Vector3 CentreScale = Vector3.one * 1.5f;
    public List<Transform> itemList;
    Transform tempCentre;//当前居中物体
    bool isDrag = false, isAdsorption, isScale, isLRBtn;//拖拽更换当前索引,控制吸附居中,控制缩放,控制左右按钮
    float MaxDis, MinDis;//最大最小距离
    private Vector3 startPos, endPos, BtnPos;//左边限制位置,右边限制位置 

    float itemDis;
    private void Awake() { }
    void Start()
    {
        ApplyEqualSpacing();//根据默认第一个位置根据设置刷新一遍坐标

        isScale = true;
        isAdsorption = true;
        tempCentre = itemList[0];
        if (tempCentreName) { tempCentreName.text = tempCentre.name; }
     
        if (tempHVType == HVType.Horizontal)
        {
            startPos = itemList[0].position;
            startPos.x -= itemList[0].GetComponent<RectTransform>().rect.width;

            endPos = itemList[itemList.Count - 1].position;
            endPos.x += itemList[itemList.Count - 1].GetComponent<RectTransform>().rect.width;
        }
        else
        {
            startPos = itemList[0].position;
            startPos.y += itemList[0].GetComponent<RectTransform>().rect.height;
         
            endPos = itemList[itemList.Count - 1].position;
            endPos.y -= itemList[itemList.Count - 1].GetComponent<RectTransform>().rect.height;
        }
  

        //设置第一个坐标与最后一个坐标位置  
        //求出最远距离
        MinDis = Vector3.Distance(itemList[0].position, Centre.position);
        for (int i = 0; i < itemList.Count; i++)
        {
            var dis = Vector3.Distance(itemList[i].position, Centre.position);
            if (dis > MaxDis)
            {
                MaxDis = dis;

            }
            else if (dis < MinDis) { MinDis = dis; }

        }
        if (Left)
        {
            Left.onClick.AddListener(LBtn);
            Right.onClick.AddListener(RBtn);
        }

        isDrag = true;


    }
    float current = 0, current2;//当前最后一位的坐标
    void ApplyEqualSpacing()
    {
        // 计算总宽度
        float totalWidth = 0f;
        foreach (RectTransform element in itemList)
        {
            if (tempHVType == HVType.Horizontal)
                totalWidth += element.sizeDelta.x;
            else
            {
                totalWidth += element.sizeDelta.y;
            }
        }
        // 计算间隔的总宽度
        float totalSpacing = (itemList.Count - 1) * SpacingDistance;
        // 计算每个元素的平均宽度
        float averageWidth = (totalWidth + totalSpacing) / itemList.Count;
        // 设置每个元素的位置
        if (tempHVType == HVType.Horizontal)
        {
            current = itemList[0].GetComponent<RectTransform>().anchoredPosition.x;
            current2 = itemList[0].GetComponent<RectTransform>().anchoredPosition.x;
        }

        else
        {
            current = itemList[0].GetComponent<RectTransform>().anchoredPosition.y;
            current2 = itemList[0].GetComponent<RectTransform>().anchoredPosition.y;
        }
        for (int i = 0; i < itemList.Count; i++)
        {
            RectTransform element = itemList[i].GetComponent<RectTransform>();
            if (tempHVType == HVType.Horizontal)
            {
                float elementWidth = element.sizeDelta.x;
                // 设置元素的位置
                element.anchoredPosition = new Vector2(current + elementWidth / 2f, element.anchoredPosition.y);
                // 更新下一个元素的X坐标
                current += elementWidth + SpacingDistance;
            }
            else
            {
                float elementWidth = element.sizeDelta.y;
                // 设置元素的位置
                element.anchoredPosition = new Vector2(element.anchoredPosition.x, current + elementWidth / 2f);
                // 更新下一个元素的X坐标
                current -= elementWidth + SpacingDistance;
            }
        }
        
    }
    void Islimit() //设置坐标切换与列表内元素与面板层级切换 保证层级与列表内数据同步
    {
        if (isDrag)
        {
        
            for (int i = 0; i < itemList.Count; i++)
            {
                var currentItem = itemList[i];

                if (tempHVType == HVType.Horizontal)
                {
                    var elementWidth = currentItem.GetComponent<RectTransform>().sizeDelta.x;
                    if (currentItem.position.x < startPos.x)
                    {
                        currentItem.GetComponent<RectTransform>().anchoredPosition = new Vector3(current + elementWidth / 2, 0, 0);
                        current += elementWidth + SpacingDistance;
                        current2 += SpacingDistance + elementWidth;
                    }
                    else
                   if (currentItem.position.x > endPos.x)
                    {
                        current2 -= SpacingDistance + elementWidth;
                        current -= elementWidth + SpacingDistance;
                        currentItem.GetComponent<RectTransform>().anchoredPosition = new Vector3((current2 + elementWidth / 2), 0, 0);
                    }
                }
                else
                {
                    var elementWidth = currentItem.GetComponent<RectTransform>().sizeDelta.y;

                    if (currentItem.position.y > startPos.y)//向下托 当前坐标比初始坐标高
                    {

                
                        currentItem.GetComponent<RectTransform>().anchoredPosition = new Vector3(currentItem.GetComponent<RectTransform>().anchoredPosition.x, (current + elementWidth / 2), 0);

                        current -= elementWidth + SpacingDistance;
                        current2 -= SpacingDistance + elementWidth;
                    }
                    else
                    if (currentItem.position.y < endPos.y)//向下托 当前坐标比终点坐标高
                    {
                        current2 += SpacingDistance + elementWidth;
                        current += elementWidth + SpacingDistance;
                        currentItem.GetComponent<RectTransform>().anchoredPosition = new Vector3(currentItem.GetComponent<RectTransform>().anchoredPosition.x, (current2 + elementWidth / 2), 0);
                    }
                }
            }
        }
    }
    void ScaleDistance()//根据百分比设置缩放动画
    {
        if (isScale)
        {
            if (tempCentre)
            {
                for (int i = 0; i < itemList.Count; i++)
                {
                    if (tempCentre == itemList[i])
                    {
                        var scale = Vector3.Lerp(itemList[i].localScale, CentreScale, Speed * Time.deltaTime);
                        tempCentre.localScale = scale;
                        if (Vector3.Distance(tempCentre.localScale, CentreScale) < 0.01f)
                        {
                            isLRBtn = false;
                            isScale = false;
                        }
                    }
                    else
                    {
                        var scale = Vector3.Lerp(itemList[i].localScale, Vector3.one, Speed * Time.deltaTime);
                        itemList[i].localScale = scale;
                    }
                }
            }
        }
    }
    void Adsorption() //停止滑动进行吸附
    {
        if (isAdsorption)
        {
            if (tempCentre)
            {
                var dis = Centre.position - tempCentre.position;
                if (tempHVType == HVType.Horizontal)
                {
                    var pos = Vector3.Lerp(Content.position, new Vector3(Content.position.x + dis.x,
                  Content.position.y, Content.position.z), Speed * Time.deltaTime);
                    Content.position = pos;
                    if (Vector3.Distance(new Vector3(Content.position.x + dis.x,
                        Content.position.y, Content.position.z), Content.position) < 0.01f)
                    {
                        isAdsorption = false;
                    }
                }
                else
                {
                    var pos = Vector3.Lerp(Content.position, new Vector3(Content.position.x,
                    Content.position.y + dis.y, Content.position.z), Speed * Time.deltaTime);

                    Content.position = pos;

                    if (Vector3.Distance(new Vector3(Content.position.x,
                        Content.position.y + dis.y, Content.position.z), Content.position) < 0.01f)
                    {
                        isAdsorption = false;
                    }
                }
            }
        }
    }
    public void LBtn()
    {
        if (!isLRBtn)
        {

            if (tempHVType == HVType.Horizontal)
            {
                itemDis = tempCentre.GetComponent<RectTransform>().rect.width + SpacingDistance;
                BtnPos = new Vector3(Content.position.x + itemDis,
                Content.position.y, Content.position.z);
            }
            else
            {
                itemDis = tempCentre.GetComponent<RectTransform>().rect.height + SpacingDistance;
                BtnPos = new Vector3(Content.position.x,
                Content.position.y + itemDis, Content.position.z);
            }
            Content.DOMove(BtnPos, 0.5f).OnComplete(() =>
            {
                isDrag = true;
                FindMinDis();
                isAdsorption = true;
                isScale = true;
            });
            isLRBtn = true;
        }
    }
    public void RBtn()
    {
        if (!isLRBtn)
        {

            if (tempHVType == HVType.Horizontal)
            {
                itemDis = tempCentre.GetComponent<RectTransform>().rect.width + SpacingDistance;
                BtnPos = new Vector3(Content.position.x - itemDis,
                Content.position.y, Content.position.z);
            }
            else
            {
                itemDis = tempCentre.GetComponent<RectTransform>().rect.height + SpacingDistance;
                BtnPos = new Vector3(Content.position.x,
                Content.position.y - itemDis, Content.position.z);
            }
            Content.DOMove(BtnPos, 0.5f).OnComplete(() =>
            {
                isDrag = true;
                FindMinDis();
                isAdsorption = true;
                isScale = true;
            });
            isLRBtn = true;
        }
    }
    void FindMinDis() //找出距离中心点最近的  
    {
        for (int i = 0; i < itemList.Count; i++)
        {
            float dis = Vector3.Distance(itemList[i].position, Centre.position);
            if (dis < MinDis)
            {
                tempCentre = itemList[i];
                if (tempCentreName)
                {
                    tempCentreName.text = itemList[i].name;
                }

                MinDis = dis;
            }
        }
        MinDis = 1000;
    }
    void Update()
    {
        Islimit();
      
        Adsorption();

       ScaleDistance();
    }

    public void OnBeginDrag(PointerEventData eventData)
    {

        StartPos = eventData.position;
        isAdsorption = false;
        isScale = false;

    }

    public void OnEndDrag(PointerEventData eventData)
    {


        transform.GetComponent<ScrollRect>().velocity = Vector3.one * 0.5f;
        FindMinDis();
        isAdsorption = true;
        isScale = true;
        isDrag = false;

    }
    public void OnDrag(PointerEventData eventData)
    {
        isDrag = true;
    }
}

最后说下使用了Dotween插件,完成上面的设置就可以畅快玩耍了~~

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值