unity的ugui-7.scroll view分页滚动

Posted mr.chenyuelin

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了unity的ugui-7.scroll view分页滚动相关的知识,希望对你有一定的参考价值。

用scroll view做个滑动页面

在这里插入图片描述
我们新建scroll view

Horizontal —> 水平滑动

Vertical —> 竖直滑动,取消勾选后不能滑动同时隐藏滑动条

Inertia — > 惯性 ,使用时如果被勾选,当你滑动结束后仍会产生一定的移动

操作:

在scroll view面板取消勾选 Vertical,只让它你水平滑动即可

在scroll view->viewport的content添加两个组件

grid layout group:可以调节content子物体的大小及排列分布
content size fitter:使子物体适配这个网格大小

在这里插入图片描述
padding:调节与边缘的距离
ceil size:每个网格大小,因为我要做的是滑动界面,直接设为父物体大小即可
spacing:每个网格的间距
start corner:upper left就是左上角开始排,start axis为horizontal就是水平排列,详情点这里
constraint:
flexible:不限制行和列的数量
flexed Row count: 限制行数
flexed column count: 限制列数

然后在content下新建两个image,将瞄点设靠左排列
效果:
在这里插入图片描述

自动轮播(分页滚动)

以水平滚动为例,你可以在content下添加4个item,将grid layout group限制为1行,防止页面竖直排列
在这里插入图片描述
在这里插入图片描述

scroll rect组件下的rect.horizontalNormalizedPosition可以显示水平滑动条的进度,0-1
而rect.verticalNormalizedPosition显示垂直滑动条的进度,是从1-0,算刻度时用1-
在这里插入图片描述
那么我们如何用数组存刻度呢?以4个页面的为例,当前第j个页面,在数组中下标为i,结果为i*(1/(n-1));其中i为下标,n为页面个数,(n-1)要转为float

手动分页滚动

就是滚动的页面,谁显示的部分多,就显示哪个页面

那么如何计算当前滑动的距离离哪个页面近呢?

做法:只需要将当前页面刻度减去滚动进度的绝对值与前者比较,记录最短距离的下标

这里会用到IEndDragHandler实现拖拽功能的接口

1.导入using UnityEngine.EventSystems;
2.并实现接口的public void OnEndDrag(PointerEventData eventData){}方法,此方法可检测鼠标拖拽的结束

全部代码:(可运行)

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
using UnityEngine.EventSystems;
using System;

public enum PageScrollType
{
    Horizontal,
    Vertical,
}

public class PageScrollView : MonoBehaviour,IBeginDragHandler,IEndDragHandler
{
    protected ScrollRect rect;
    protected int pageCount;//页面item个数
    private RectTransform content;
    protected float[] pages;//存滚动条进度

    public float moveTime = 0.3f;
    private float timer = 0;
    private float startMovePos;//开始位置
    protected int currentPage = 0;//当前页
    //是否在移动
    private bool isMoving = false;
    //是否开启自动滚动
    public bool IsAutoScroll;
    //是否正在拖拽
    private bool isDraging = false;
    public float AutoScrollTime = 2;
    private float AutoScrollTimer = 0;

    public PageScrollType pageScrollType = PageScrollType.Horizontal;

    public Action<int> onPageChange;

    // Start is called before the first frame update
    protected virtual void Start()
    {
        Init();
    }

    // Update is called once per frame
    protected virtual void Update()
    {

        ListenerMove();
        ListenerAutoScroll();
    }

    public void Init()
    {
        rect = transform.GetComponent<ScrollRect>();
        if (rect == null)
        {
            throw new System.Exception("未查询到scrollRect");
        }
        content = transform.Find("Viewport/Content").GetComponent<RectTransform>();
        if (pageCount == 1) return;
        pageCount = content.childCount;
        pages = new float[pageCount];
        //设好每个页面的刻度
        for (int i = 0; i < pages.Length; i++)
        {
            switch (pageScrollType)
            {
                case PageScrollType.Horizontal:
                    pages[i] = i * (1 / (float)(pageCount - 1));
                    break;
                case PageScrollType.Vertical:
                    pages[i] = 1 - i * (1 / (float)(pageCount - 1));
                    break;               
            }
            
        }

    }
    //监听移动
    public void ListenerMove()
    {
        if (isMoving)
        {
            timer += Time.deltaTime * (1 / moveTime);
            switch (pageScrollType)
            {
                case PageScrollType.Horizontal:
                    rect.horizontalNormalizedPosition = Mathf.Lerp(startMovePos, pages[currentPage], timer);
                    break;
                case PageScrollType.Vertical:
                    rect.verticalNormalizedPosition = Mathf.Lerp(startMovePos, pages[currentPage], timer);
                    break;
                default:
                    break;
            }
            
            if (timer >= 1)
            {
                isMoving = false;
            }
        }
    }
    //监听自动滚动
    public void ListenerAutoScroll()
    {
        if (isDraging) return;
        if(IsAutoScroll)
        {
            AutoScrollTimer += Time.deltaTime;
            if(AutoScrollTimer>=AutoScrollTime)
            {
                AutoScrollTimer = 0;
                currentPage++;
                currentPage %= pageCount;
                ScrollPage(currentPage);
            }
        }
    }
    //计算//计算出离得最近的一页
    public int CaculateMinDistancePage()
    {
        int minPage = 0;
        //计算出离得最近的一页
        for (int i = 1; i < pages.Length; i++)
        {
            float curPage = 0;
            switch (pageScrollType)
            {
                case PageScrollType.Horizontal:
                    curPage = rect.horizontalNormalizedPosition;
                    break;
                case PageScrollType.Vertical:
                    curPage = rect.verticalNormalizedPosition;
                    break;
               
            }
            if (Mathf.Abs(pages[i] - curPage) < Mathf.Abs(pages[minPage] - curPage))
            {
                minPage = i;
            }
        }
        return minPage;
    }
    //滚到哪一页
    public void ScrollPage(int page)
    {
        isMoving = true;
        this.currentPage = page;
        timer = 0;
        switch (pageScrollType)
        {
            case PageScrollType.Horizontal:
                startMovePos = rect.horizontalNormalizedPosition;
                break;
            case PageScrollType.Vertical:
                startMovePos = rect.verticalNormalizedPosition;
                break;
            
        }
        onPageChange?.Invoke(this.currentPage);
    }
    //结束拖拽滑动
    public void OnEndDrag(PointerEventData eventData)
    {
        this.ScrollPage(CaculateMinDistancePage());
        isDraging = false;
        AutoScrollTimer = 0
;    }
    //开始拖拽滑动
    public void OnBeginDrag(PointerEventData eventData)
    {
        isDraging = true;
    }
}


附加带scale属性和rotation属性的分页滚动

ScalePageScrollVIew.cs

 using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class ScalePageScrollVIew : PageScrollView
{
    protected GameObject[] items;

    public float currentScale = 1f;
    public float otherScale = 0.6f;

    public int prePage;
    public int nextPage;

    protected override void Start()
    {
        base.Start();
        items = new GameObject[pageCount];
        for(int i=0;i<pageCount;i++)
        {
            items[i] = transform.Find("Viewport/Content").GetChild(i).gameObject;
        }
    }
    protected override void Update()
    {
        base.Update();
        ListenerScale();
    }

    public void ListenerScale()
    {
        //找上一页
        for(int i=0;i<pages.Length;i++)
        {
            if(pages[i]<=rect.horizontalNormalizedPosition)
            {
                prePage = i;
            }
        }
        //下一页
        for (int i = 0; i < pages.Length; i++)
        {
            if (pages[i] > rect.horizontalNormalizedPosition)
            {
                nextPage = i;
                break;
            }
        }
        if (nextPage == prePage) return;
        //移动幅度占页面距离的比例
        float percent = (rect.horizontalNormalizedPosition - pages[prePage]) / (pages[nextPage] - pages[prePage]);
        //移动幅度越大,后面页面变大,移动幅度越小,前面页面变小
        items[prePage].transform.localScale = Vector3.Lerp(Vector3.one * currentScale, Vector3.one * otherScale, percent);
        items[nextPage].transform.localScale = Vector3.Lerp(Vector3.one * currentScale, Vector3.one * otherScale, 1 - percent);

        for (int i = 0; i < items.Length; i++)
        {
            //除了中间,其它都为0.6scale
            if(i!=prePage&&i!=nextPage)               
                items[i].transform.localScale = Vector3.one * otherScale;
        }
    }

}

Quaternion.Euler(vector3 angle):表示物体旋转的角度

RotationPageScrollView.cs

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class RotationPageScrollView : ScalePageScrollVIew
{
    public float rotation;

    protected override void Start()
    {
        base.Start();
    }
    protected override void Update()
    {
        base.Update();
        ScalePageScroll();
    }
    public void ScalePageScroll()
    {
        if (nextPage == prePage) return;
        //移动幅度占页面距离的比例
        float percent = (rect.horizontalNormalizedPosition - pages[prePage]) / (pages[nextPage] - pages[prePage]);
        //移动幅度越大,后面页面变大,移动幅度越小,前面页面变小
        items[prePage].transform.localRotation = Quaternion.Euler( -Vector3.Lerp(Vector3.zero, new Vector3(0,rotation,0), percent));
        items[nextPage].transform.localRotation = Quaternion.Euler(-Vector3.Lerp(Vector3.zero, new Vector3(0, rotation, 0), 1 - percent));

        for (int i = 0; i < items.Length; i++)
        {
            //除了中间,其它都为0.6scale
            if (i != prePage && i != nextPage)
            {
                if(i>currentPage)
                {
                    items[i].transform.localRotation = Quaternion.Euler(new Vector3(0, rotation, 0));
                    
                }
                else if(i<currentPage)
                {
                    items[i].transform.localRotation = Quaternion.Euler(new Vector3(0, -rotation, 0));
                }
                else
                {
                    items[i].transform.localRotation = Quaternion.Euler(new Vector3(0, 0, 0));
                }
            }
        }
    }
}

以上是关于unity的ugui-7.scroll view分页滚动的主要内容,如果未能解决你的问题,请参考以下文章

分享Unity的Profiler分析和解决GC.MarkDependencies

Appcenter Android Build for React-Native with Unity

Unity 中的 AI 角色与 Photon View

Unity Scroll View图文混编并自适应范围

Unity3D 灵巧小知识点☀️ | Unity UGUI组件Scroll View禁止 左右 或 上下 滑动

Unity 实用工具✨| Unity 十款 浏览器相关插件 整理(web view / browser)