unity UGUI无限循环滚动居中

最近在做一个ui循环滚动的功能,网上找了半天脚本感觉都和我实际需求不太符合,自己花费一些时间完成了这个功能记录一下。下面开始正题
我是采用unity自带组件Scroll View来完成,首先设置Scroll View如下图
我是横屏你可以根据情况选择你的
面板层级结构如下
层级面板结构
然后开始编写代码,我就直接贴了,不懂可以看一下注释。

using DG.Tweening;
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 != null ) { tempCentreName.text = tempCentre.name; }
       
        if (tempHVType == HVType.Horizontal)
        {
            startPos = itemList[0].position;
            startPos.x -= itemList[0].GetComponent<RectTransform>().rect.width + itemList[0].GetComponent<RectTransform>().rect.width / 2;
            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 + itemList[0].GetComponent<RectTransform>().rect.height / 2;
            endPos = itemList[itemList.Count - 1].position;
            endPos.y -= itemList[itemList.Count - 1].GetComponent<RectTransform>().rect.height;
            //print(endPos);
        }
        //设置第一个坐标与最后一个坐标位置  
        //求出最远距离
        for (int i = 0; i < itemList.Count; i++)
        {
            var dis = Vector3.Distance(itemList[i].position, Centre.position);
            if (dis > MaxDis)
            {
                MaxDis = dis;
                MinDis = dis;
            }
        }
        if (Left)
        {
            Left.onClick.AddListener(LBtn);
            Right.onClick.AddListener(RBtn);
        }
        isDrag = true;
    }
    float currentX = 0, currentX2;//当前最后一位的坐标
    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;
        // 设置每个元素的位置
        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(currentX + elementWidth / 2f, element.anchoredPosition.y);
                // 更新下一个元素的X坐标
                currentX += elementWidth + SpacingDistance;
            }
            else
            {
                float elementWidth = element.sizeDelta.y;
                // 设置元素的位置
                element.anchoredPosition = new Vector2(element.anchoredPosition.x, currentX + elementWidth / 2f);
                // 更新下一个元素的X坐标
                currentX -= 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(currentX + elementWidth / 2, 0, 0);
                        currentX += elementWidth + SpacingDistance;
                        currentX2 += SpacingDistance + elementWidth;
                    }
                    else
                   if (currentItem.position.x > endPos.x)
                    {
                        currentX2 -= SpacingDistance + elementWidth;
                        currentX -= elementWidth + SpacingDistance;
                        currentItem.GetComponent<RectTransform>().anchoredPosition = new Vector3((currentX2 + elementWidth / 2), 0, 0);
                    }
                }
                else
                {
                    var elementWidth = currentItem.GetComponent<RectTransform>().sizeDelta.y;                
                    if (currentItem.position.y > startPos.y)//向下托 当前坐标比初始坐标高
                    {                 
                        currentItem.GetComponent<RectTransform>().anchoredPosition = new Vector3(0, (currentX + elementWidth / 2), 0);
                        currentX -= elementWidth + SpacingDistance;
                        currentX2 -= SpacingDistance + elementWidth;
                    }
                    else
                    if (currentItem.position.y < endPos.y)//向下托 当前坐标比终点坐标高
                    {
                        currentX2 += SpacingDistance + elementWidth;
                        currentX += elementWidth + SpacingDistance;
                        currentItem.GetComponent<RectTransform>().anchoredPosition = new Vector3(0, (currentX2 + 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)
        {
            Controller.JTtime = 0;
            Controller.JianT.gameObject.SetActive(false);    
            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)
        {
            Controller.JTtime = 0;
            Controller.JianT.gameObject.SetActive(false);
            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();
        ScaleDistance(); 
        Adsorption();
    }

    public void OnBeginDrag(PointerEventData eventData)
    {
      
        StartPos = eventData.position;
        isAdsorption = false;
        isScale = false;
        Controller.JTtime = 0;
        Controller.JianT.gameObject.SetActive(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;
    }
}

下面这个是脚本设置,主要关注的就是公开的变量我都有注释,结合上面的面板图很轻易就能看出来,间隔距离是两个图片之间的距离,缩放倍数是中间最大是多少倍,根据你工程设置,默认设置1就可以了,最后面的text是显示居中ui的名字,名字的设置是根据图片名称来的
在这里插入图片描述
最后说下使用了Dotween插件,完成上面的设置就可以畅快玩耍了~~

  • 2
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
要实现Unity UGUI中的ScrollView滑动居中放大,其他的缩小,可以按照以下步骤进行操作: 1. 创建一个ScrollView,用于显示内容,并设置合适的大小和位置。 2. 在ScrollView中创建一个Content对象,用于放置所有需要显示的子对象,并设置Layout Group组件,以确保内容按照一定的布局排列。 3. 在每个子对象上添加一个自定义的脚本,用于控制子对象的缩放和位置。脚本中需要包含以下几个要点: a. 监听ScrollView的滑动事件,获取当前的滑动位置。 b. 根据当前滑动位置,计算每个子对象在滑动过程中应该设置的缩放比例。例如,距离居中的子对象应该更大,而距离边缘的子对象应该更小。 c. 根据计算得到的缩放比例,分别对每个子对象进行缩放设置。可以使用RectTransform的scale属性来实现缩放功能。 d. 根据子对象的缩放比例和位置信息,将子对象移动到ScrollView的合适位置。可以使用RectTransform的anchoredPosition属性来实现位置调整。 e. 可以根据需要,在脚本中添加其他的功能,例如点击子对象时的反应等。 4. 将自定义的脚本添加到所有的子对象上,确保每个子对象都能根据滑动进行缩放和位置调整。 通过以上步骤,我们可以实现在Unity UGUI中的ScrollView滑动过程中,距离居中的子对象放大,而距离边缘的子对象缩小的效果。具体的缩放比例和位置调整可以根据实际需求进行调整。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值