Unity3d C#实现基于UGUI ScrollRect的轮播图效果功能(含源码)

前言

轮播功能是一种常见的页面组件,用于在页面中显示多张图片/素材并自动或手动进行切换,以提高页面的美观度和用户体验。主要的功能是:自动/手动切换;平滑的切换效果;导航指示器等。可惜Unity的UGUI系统里没有现成的实现该功能,所以这里直接基于ScrollRect来实现该组件功能。在上述功能上新增了无限轮播、鼠标悬停暂停轮播、鼠标拖拽轮播、竖向轮播等功能。

硬广

自制3D版三维搭建俄罗斯方块WX小游戏,走过路过可以扫描支持。
在这里插入图片描述
三维的消除,地域难度:
在这里插入图片描述

效果

左右轮播:
在这里插入图片描述

上下轮播:
在这里插入图片描述

导航器轮播:
在这里插入图片描述

拖拽轮播:
在这里插入图片描述

实现

实现的思路是基于UGUI的ScrollRect组件用于滑动效果,而其中的HorizontalLayoutGroup
或者VerticalLayoutGroup对Content的内容进行排序,其实无限循环的轮播思路参考之前编写的
《Unity3d C# UGUI实现一个自动循环滚动的列表(ScrollRect)》 (https://blog.csdn.net/qq_33789001/article/details/120813324),平滑的切换效果是使用移动的动画效果(插件DOTweenPro),其余的核心就是轮播的时候对Content的位置进行计算和移动。以下是部分实现的过程。工程基于Unity3d 2020.3.28f1c1版本实现。

UI搭建

UI的整体搭建以常用的从右至左的轮播为基础,效果如下:
在这里插入图片描述

其中最外层为ScrollRect组件,Content上新增了Horizontal Layout Group用于子节点排序和Content Size Fitter用于宽度适配。详细设置如下:
在这里插入图片描述

其中需要特别注意的是padding left/right最好相等,Spacing也最好一致,如果设置不一致可能导致功能失效或者异常。
NodeTips下的节点是导航器的小图标,一个选中的图(Sel)和一个未选中的图(UnSel),并使用了Horizontal Layout Group进行了排序:
在这里插入图片描述

配置参数

为了保持插件的灵活性和适用性,设定了很多配置参数:

    [Header("自动轮播方向")]
    public SwipeDir swipeDir = SwipeDir.RightToLeft;   

    [Header("启用自动轮播")]
    public bool enbaleAuto = true;

    [Header("启用拖拽")]
    public bool enbaleDrag = true;


    [Header("轮播阀值(超出多少个元素)")]
    [Range(1, 20)]
    public int ItemNum = 1;

    [Header("自动轮播间隔")]
    public float swipeDura = 5f;

    [Header("轮播动画时间")]
    public float swipeTime = 0.5f;

这些暴露出来的参数,可以在Inspector窗口进行灵活配置:
在这里插入图片描述

事件处理

这里鼠标滑动的操作依托于ScrollRect组件,而鼠标进入取消轮播,鼠标移出恢复轮播,鼠标拖拽释放置中节点等操作都需要对事件进行处理,这里使用了EventTrigger来实现,监听了鼠标进入、移出、开始拖拽、结束拖拽等事件,监听代码如下:

        AddETEvent(et, EventTriggerType.PointerEnter, OnPointerIn);
        AddETEvent(et, EventTriggerType.PointerExit, OnPointerOut);
        AddETEvent(et, EventTriggerType.BeginDrag, OnBeginDrag);
        AddETEvent(et, EventTriggerType.EndDrag, OnEndDrag);
    private void AddETEvent(EventTrigger et, EventTriggerType ei, UnityAction<BaseEventData> ua)
    {
        UnityAction<BaseEventData> action = ua;
        EventTrigger.Entry entry = new EventTrigger.Entry();
        entry.eventID = ei;
        entry.callback.AddListener(action);
        et.triggers.Add(entry);
}

轮播方向

虽然常用的轮播是从右至左的操作,不过偶尔还是会有从左至右和上下轮播的需求情况,这里一共定义了四个方向:

public enum SwipeDir
{
    BottomToTop = 1,
    TopToBottom = 2,
    LeftToRight = 3,
    RightToLeft = 4
}

导航器

导航器是轮播器下方的提示小图标按钮,在轮播的节点出现后,需要初始化一下导航器,导航器会根据轮播的节点进行生成排序:

    void refreshTipsState() {
        for (int j = 0; j < tipList.Count; j++)
        {
            tipList[j].gameObject.SetActive(tipList[j].refItem ? tipList[j].refItem.gameObject.activeSelf:false);
            if (nowCenterNode == tipList[j].refItem)
                tipList[j].Selected();
            else
                tipList[j].Unselected();
        }
}

导航器初始化完成后,在鼠标点击后,导航器会根据轮播结果刷新导航器,当自动轮播开始时,也会刷新导航器:

    void refreshTipsState() {
        for (int j = 0; j < tipList.Count; j++)
        {
            tipList[j].gameObject.SetActive(tipList[j].refItem ? tipList[j].refItem.gameObject.activeSelf:false);
            if (nowCenterNode == tipList[j].refItem)
                tipList[j].Selected();
            else
                tipList[j].Unselected();
        }
    }

轮播功能

在自动轮播的过程中,到轮播时间时,会执行轮播过程;或者当手动拖拽轮播图时,拖拽结束后,也会执行轮播过程。轮播的过程就是将滚动内容移动至中心节点居中的位置,所以整个过程都是围绕获取中心节点,计算节点居中位置和移动到目标位置来实现的:

//执行轮播的动作
void doMoveToCenterNode(Transform tran)
{
    refreshTipsState();
    nowCenterNode = tran;
    int idx = getNodeActiveIndex(tran); // tran.GetSiblingIndex();
    if (idx < 0 || idx >= hvLayoutGroup.transform.childCount)
        return;
    Vector3 tPos;
    switch (swipeDir)
    {
        case SwipeDir.BottomToTop:
            tPos = new Vector3(initPos.x, hvLayoutGroup.padding.top + (Space + itemHeight) * (idx + 1) - scrolltran.rect.height , initPos.z);
            break;
        case SwipeDir.TopToBottom:
            tPos = new Vector3(initPos.x, hvLayoutGroup.padding.top + (Space + itemHeight) * (idx + 1) - scrolltran.rect.height, initPos.z);
            break;
        case SwipeDir.LeftToRight:
            tPos = new Vector3(scrolltran.rect.width - hvLayoutGroup.padding.left - (Space + itemWidth) * (idx + 1), initPos.y, initPos.z);
            //new Vector3(LayoutGroup.padding.right + (Space + itemWidth) * (idx + 1) - scrolltran.rect.width, initPos.y, initPos.z);
            break;
        case SwipeDir.RightToLeft:
            tPos = new Vector3(scrolltran.rect.width - hvLayoutGroup.padding.left - (Space + itemWidth) * (idx + 1), initPos.y, initPos.z);
            break;
        default:
            tPos = new Vector3(scrolltran.rect.width - hvLayoutGroup.padding.left - (Space + itemWidth) * (idx + 1), initPos.y, initPos.z);
            break;
    }
    scrollrect.content.DOKill();
    scrollrect.content.DOAnchorPos3D(tPos, swipeTime);
}

这里的tPos就是移动的目标位置,计算这个数值和轮播方向有关,更和Content的RectTransform设定有关,结合HorizontalLayoutGroup的padding 和spacing设定进行计算。

工程源码

包含Unity3d 工程源码 以及unitypackage包。
https://download.csdn.net/download/qq_33789001/89507901

连接打不开说明审核未通过,稍后重试。

  • 21
    点赞
  • 13
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

十幺卜入

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值