利用UGUI实现分页滚动效果

在游戏中,无论是显示活动或者是任务,分页滚动显示都是一个常见的功能.使用UGUI的Scroll view来实现一个这样的功能是在unity中比较常见的实现方式.

Scroll view的设置

  • 在Scroll view的content中添加如下俩个组件,可以通过调节grid layout group组件中的cell size来调节没一个分页里的元素的大小.
    在这里插入图片描述
  • 如果只需要水平分页移动,可以将Scroll View组件的vertic垂直选项关闭在这里插入图片描述
  • 在content下添加image作为每一个页面,这样就可以通过手动移动的方式实现了一个简单的滑动页面.
    在这里插入图片描述

实现自我滚动的功能

  • 上述实现,由于Scroll view的设置,滑动过程中其可能会处在两个页面的中间,在实际游戏中,对于这中功能,当滑动结束时,只能处于一个界面,不会出现如下情况,如下:
    在这里插入图片描述
  • 实现滚动可以通过Scroll view下的Scroll Rect组件来实现.
    通过得到Scroll view下的Scroll Rect组件,打印scrollRect.horizontalNormalizedPosition属性,发现当存在两个页面时,处于第一个界面的时候scrollRect.horizontalNormalizedPosition=0,处于第二个界面的时scrollRect.horizontalNormalizedPosition=1.
    在这里插入图片描述
  • 当存在三个页面的时候,第一个页面为0,第二个页面为0.5,第三个页面为1
    我们可以同过这个属性来实现移动到哪个界面的功能.
  • 假设总共有n个页面,则第n个为1,前n-1个平分1,则第i个的scrollRect.horizontalNormalizedPosition为 i*1/n-1.可以通过修改scrollRect.horizontalNormalizedPosition的值来修改移动.
  • 如下代码添加到scroll view 控件上,即可实现一个简单的分页滚动功能
    包括,自动滚动,以及移动页面的时候,跳转到最近的页面.
public class PageScrollView : MonoBehaviour,IBeginDragHandler,IEndDragHandler
{
    // Start is called before the first frame update
    #region
    protected ScrollRect scrollRect;
    private int pageCount;
    //每个页面的horizontalNormalizedPosition值
    public float[] pageHorizontal;
    //是否自动跳转
    public bool isau=true;
    //自动跳转的时间间隔,以及计数器
    public float auTime = 2;
    private float auTimer = 0;

    //是否跳转
    private bool isjump = false;
    //当前的页面下标
    private int currentpageindex;
    //开始的页面位置
    private float startHorizontal;
    #endregion
    //跳转需要的时间
    private float jumpTime = 0.3f;
    private float jumpTimer=0;

    //在拖拽的时候,不进行自动滚动
    private bool isdraging = false;
    //跳转到具体页面的时候,进行相应的事件回调
    public Action<int> pagehandle;

    void Start()
    {
        scrollRect = GetComponent<ScrollRect>();
        if(scrollRect==null)
        {
            throw new System.Exception("没有该组件");
        }
        pageCount = transform.Find("Viewport/Content").childCount;
        pageHorizontal = new float[pageCount];
        for(int i=0;i<pageCount;i++)
        {
            pageHorizontal[i] = i * 1.0f / (float)(pageCount - 1);
        }
    }

    // Update is called once per frame
    void Update()
    {
        listenJump();
        Listenantojump();
    }
    //处理自动跳转逻辑
    void Listenantojump()
    {
        if (isdraging == true)
            return;
        if(isau)
        {
            auTimer += Time.deltaTime;
            if(auTimer>=auTime)
            {
                auTimer = 0;
                currentpageindex++;
                currentpageindex %= pageCount;
                pagejump(currentpageindex);
            }
        }
    }

    void pagejump(int pageindex)
    {
        isjump = true;
        jumpTimer = 0;
        this.currentpageindex = pageindex;
        startHorizontal = scrollRect.horizontalNormalizedPosition;
        if (pagehandle != null)
            pagehandle(currentpageindex);
    }
    void listenJump()
    {
        if(isjump)
        {
            jumpTimer += Time.deltaTime * (1 / jumpTime);
            //通过线性插值的方式修改horizontalNormalizedPosition的值来达到移动的效果
            scrollRect.horizontalNormalizedPosition = Mathf.Lerp(startHorizontal, pageHorizontal[currentpageindex], jumpTimer);
            if(jumpTimer>=1)
            {
                isjump = false;
            }
        }
    }
    //通过监听拖拽事件,跳转到松开手的时候离得最近的页面
    public void OnEndDrag(PointerEventData eventData)
    {
        int minpageindex = 0;
        //float nowhe = scrollRect.horizontalNormalizedPosition;
        for(int i=1;i<pageCount;i++)
        {
            if(Mathf.Abs(scrollRect.horizontalNormalizedPosition - pageHorizontal[i])< Mathf.Abs(pageHorizontal[minpageindex] - scrollRect.horizontalNormalizedPosition))
            {
                minpageindex = i;
            }
        }
        pagejump(minpageindex);
        isdraging = false;
        //结束拖曳后,要过2s才会进行页面滚动
        auTimer = 0;
    }

    public void OnBeginDrag(PointerEventData eventData)
    {
        isdraging = true;
    }
}

对代码进行修改,让其变得通用

  • 上述代码实现,只能在水平方向进行滚动,再垂直方向上不能滚动.稍作修改可以实现在垂直方向上也进行分页滚动.
public enum ScrllViewType
{
    Horizontal,
    Vertical
}
public class PageScrollView : MonoBehaviour,IBeginDragHandler,IEndDragHandler
{
    // Start is called before the first frame update
    #region
    protected ScrollRect scrollRect;
    private int pageCount;
    //每个页面的horizontalNormalizedPosition值
    public float[] pageHorizontal;
    //是否自动跳转
    public bool isau=true;
    //自动跳转的时间间隔,以及计数器
    public float auTime = 2;
    private float auTimer = 0;

    //是否跳转
    private bool isjump = false;
    //当前的页面下标
    private int currentpageindex;
    //开始的页面位置
    private float startHorizontal;
    #endregion
    //跳转需要的时间
    private float jumpTime = 0.3f;
    private float jumpTimer=0;

    //在拖拽的时候,不进行自动滚动
    private bool isdraging = false;
    //跳转到具体页面的时候,进行相应的事件回调
    public Action<int> pagehandle;

    public ScrllViewType scrllViewType = ScrllViewType.Horizontal;

    void Start()
    {
        scrollRect = GetComponent<ScrollRect>();
        if(scrollRect==null)
        {
            throw new System.Exception("没有该组件");
        }
        pageCount = transform.Find("Viewport/Content").childCount;
        pageHorizontal = new float[pageCount];

        switch (scrllViewType)
        {
            case ScrllViewType.Horizontal:
                for (int i = 0; i < pageCount; i++)
                {
                    pageHorizontal[i] = i * 1.0f / (float)(pageCount - 1);
                }
                break;
            //对于垂直移动来说,假设有三个页面,第一个的scrollRect.verticalNormalizedPosition是1,第二个是0.5,第三个是0
            case ScrllViewType.Vertical:
                for (int i = 0; i < pageCount; i++)
                {
                    pageHorizontal[i] = 1-i * 1.0f / (float)(pageCount - 1);
                }
                break;
        }
        
    }

    // Update is called once per frame
    void Update()
    {
        listenJump();
        Listenantojump();
    }
    //处理自动跳转逻辑
    void Listenantojump()
    {
        if (isdraging == true)
            return;
        if(isau)
        {
            auTimer += Time.deltaTime;
            if(auTimer>=auTime)
            {
                auTimer = 0;
                currentpageindex++;
                currentpageindex %= pageCount;
                pagejump(currentpageindex);
            }
        }
    }

    void pagejump(int pageindex)
    {
        isjump = true;
        jumpTimer = 0;
        this.currentpageindex = pageindex;
        switch (scrllViewType)
        {
            case ScrllViewType.Horizontal:
                startHorizontal = scrollRect.horizontalNormalizedPosition;
                break;
            case ScrllViewType.Vertical:
                startHorizontal = scrollRect.verticalNormalizedPosition;
                break;
        }
        
        if (pagehandle != null)
            pagehandle(currentpageindex);
    }
    void listenJump()
    {
        if(isjump)
        {
            jumpTimer += Time.deltaTime * (1 / jumpTime);
            //通过线性插值的方式修改horizontalNormalizedPosition的值来达到移动的效果
            switch (scrllViewType)
            {
                case ScrllViewType.Horizontal:
                    scrollRect.horizontalNormalizedPosition = Mathf.Lerp(startHorizontal, pageHorizontal[currentpageindex], jumpTimer);
                    break;
                case ScrllViewType.Vertical:
                    scrollRect.verticalNormalizedPosition = Mathf.Lerp(startHorizontal, pageHorizontal[currentpageindex], jumpTimer);
                    break;
            }
            if(jumpTimer>=1)
            {
                isjump = false;
            }
        }
    }
    //通过监听拖拽事件,跳转到松开手的时候离得最近的页面
    public void OnEndDrag(PointerEventData eventData)
    {
        int minpageindex = 0;
        //float nowhe = scrollRect.horizontalNormalizedPosition;
        switch (scrllViewType)
        {
            case ScrllViewType.Horizontal:
                for (int i=1;i<pageCount;i++)
                {
                    if(Mathf.Abs(scrollRect.horizontalNormalizedPosition - pageHorizontal[i])< Mathf.Abs(pageHorizontal[minpageindex] - scrollRect.horizontalNormalizedPosition))
                    {
                        minpageindex = i;
                     }
                }
                break;
            case ScrllViewType.Vertical:
                for (int i = 1; i < pageCount; i++)
                {
                    if (Mathf.Abs(scrollRect.verticalNormalizedPosition - pageHorizontal[i]) < Mathf.Abs(pageHorizontal[minpageindex] - scrollRect.verticalNormalizedPosition))
                    {
                        minpageindex = i;
                    }
                }
                break;
        }
        
        pagejump(minpageindex);
        isdraging = false;
        //结束拖曳后,要过2s才会进行页面滚动
        auTimer = 0;
    }

    public void OnBeginDrag(PointerEventData eventData)
    {
        isdraging = true;
    }
}
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值