Unity系列——构建pageView翻页容器

做ui系统的时候,经常会使用到翻页容器。这边自己封装了一个,主要是根据监听滑动,ScrollRect的horizontalNormalizedPosition属性来实现插值。

实现了动态加载page,可以动态创建格子,每个创建有相应的回调,也有翻页的回调。代码:

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

/// 
/// @desc:      翻页容器,继承接口:IBeginDragHandler(开始拖拽),IEndDragHanler(结束拖拽),IDragHandler(拖拽中)
/// @author:    Rambo
/// @use        基于ugui5.3.6 通过创建Scroll View,并在Content添加组件content size fitter设置Hori fit为preferred size,
///             添加组件horizontal layout group,并在Content下添加翻页模板defPage,为defPage添加layout element,设置属性
///             preferred width和preferred height。格子翻页就为defPage添加layout group。
/// @use        代码初始化InitPage,根据需求选择 格子LayoutGrid或者普通LayoutNorPage   
/// 
public class PageView : MonoBehaviour, IBeginDragHandler, IEndDragHandler
{
    private ScrollRect rect;                        //滑动组件
    private int currentPageIndex = -1;              //当前页下标
    private float targethorizontal = 0;             //滑动的起始坐标
    private bool isDrag = false;                    //是否拖拽结束

    private float startime = 0f;                    //开始时间 
    private float delay = 0.1f;                     //延时时间

    private int maxPageNum = 0;                     //最大页数
    private GameObject defPage;                     //默认翻页模板
    private int createPage = 0;                     //已创建页数

    private GameObject defGrid;                     //格子模板    
    private int row;                                //行
    private int column;                             //列
    private bool layoutGridItem = false;                        //是否为格子容器
    private List gridList = new List(); //格子翻页的每个格子存储

    private List pageList = new List(); //翻页容器存储
    private List posList = new List();            //求出每页的临界角,页索引从0开始

    /// 
    /// 用于返回一个页码,-1说明没有数据,页码从0开始
    /// 
    public Action OnPageChanged;
    /// 
    /// 创建小孩的回调,返回的下标从0开始
    /// 
    public Action CreateItemCall;
    public float smooting = 4;      //滑动速度

    #region 私有函数处理
    //重设页码坐标list
    private void UpdatePosList()
    {
        posList.Clear();
        for (int i = 0; i < createPage; i++)
        {
            float page = i / ((float)(createPage - 1));
            posList.Add(page);
        }
    }

    //是否要创建翻页容器
    private void IsCreatePage()
    {
    
        if (currentPageIndex+1 == createPage)
        {
            if (layoutGridItem)
            {
                CreateGridPage();
            }
            else
            {
                CreateNorPage();
            }
        }

    }

    //设置当前容器所在页
    private void SetPageIndex(int index)
    {

        if (index != currentPageIndex)
        {
            currentPageIndex = index;
            if (OnPageChanged != null)
            {
                OnPageChanged(currentPageIndex);
            }

            //StartCoroutine(DelayContinue());
            IsCreatePage();
        }

    }

    //创建翻页容器
    private void CreatePageItem()
    {
        GameObject sPage = GameObject.Instantiate(defPage);
        sPage.gameObject.SetActive(true);
        sPage.transform.SetParent(defPage.transform.parent);
        sPage.transform.localScale = Vector3.one;
        sPage.transform.localPosition = Vector3.zero;

        pageList.Insert(createPage, sPage);
        createPage += 1;
        UpdatePosList();
    }
    #endregion

    #region 滑动处理
    /// 
    /// 开始滑动
    /// 
    /// 
    public void OnBeginDrag(PointerEventData eventData)
    {
        isDrag = true;
    }

    /// 
    /// 滑动结束
    /// 
    /// 
    public void OnEndDrag(PointerEventData eventData)
    {

        float posX = rect.horizontalNormalizedPosition;
        int index = 0;
        //假设离第一位最近
        float offset = Mathf.Abs(posList[index] - posX);
        for (int i = 1; i < posList.Count; i++)
        {
            float temp = Mathf.Abs(posList[i] - posX);
            if (temp < offset)
            {
                index = i;

                //保存当前的偏移量
                //如果到最后一页。反翻页。所以要保存该值
                offset = temp;
            }
        }


        //因为这样效果不好。没有滑动效果。比较死板。所以改为插值
        //rect.horizontalNormalizedPosition = page[index];

        //动态创建小孩,并进行翻页通知
        SetPageIndex(index);

        targethorizontal = posList[index]; //设置当前坐标,更新函数进行插值
        isDrag = false;

    }
    #endregion

    #region 创建格子翻页
    /// 
    /// 根据pos获取格子父节点GameObject
    /// 
    /// 下标从0开始
    /// 
    public GameObject GetGridParentByPos(int pos)
    {
        var num = row * column;
        GameObject curPage = defPage.gameObject;
        int page = Mathf.CeilToInt(pos / num);
        if (pageList.Count >= page && page >= 0)
        {
            curPage = pageList[page];
            
        }
        return curPage;
    }

    /// 
    /// 初始格子翻页容器
    /// 
    /// 格子模板
    /// 行
    /// 列
    public void LayoutGrid(GameObject gridItem, int myRow, int myColumn)
    {
        layoutGridItem = true;
        defGrid = gridItem;
        row = myRow;
        column = myColumn;

        for (int i = 0; i < 2; i++)
        {
            CreateGridPage();
        }
    }

    //创建格子翻页
    private void CreateGridPage()
    {
        if(createPage >= maxPageNum)
        {
            return;
        }
        CreatePageItem();

        var showNum = row * column;
        var sPos = (createPage - 1) * showNum;
        var endPos = createPage * showNum;

        for (int i = sPos; i < endPos; i++)
        {
            GameObject cGrid = GameObject.Instantiate(defGrid);
            GameObject obj = GetGridParentByPos(i);
            cGrid.SetActive(true);
            cGrid.transform.SetParent(obj.transform);
            cGrid.transform.localScale = Vector3.one;
            cGrid.transform.localPosition = Vector3.zero;

            gridList.Insert(i, cGrid);
            if (CreateItemCall!=null)
            {
                CreateItemCall(cGrid, i);
            } 
        }
    }
    #endregion

    #region 创建普通翻页
    /// 
    /// 初始化普通翻页
    /// 
    public void LayoutNorPage()
    {
        for (int i = 0; i < 2; i++)
        {
            CreateNorPage();
        }
    }

    //创建普通翻页
    private void CreateNorPage()
    {
        if (createPage >= maxPageNum)
        {
            return;
        }
        CreatePageItem();
        if (CreateItemCall != null)
        {
            CreateItemCall(pageList[createPage - 1], createPage - 1);
        } 
    }
    #endregion

    /// 
    /// 初始化pageview
    /// 
    /// 翻页容器模板,构建时必须添加在content下,每次复制添加时是拿模板的父节点
    /// 翻页容器的总页数
    public void InitPage(GameObject defItem, int maxPage)
    {
        maxPageNum = maxPage;
        defPage = defItem;
    }

    // Use this for initialization
    void Start()
    {
        rect = transform.GetComponent();     
        startime = Time.time;
    }

    //更新函数
    void Update()
    {
        if (Time.time < startime + delay) return;
        //如果不判断。当在拖拽的时候要也会执行插值,所以会出现闪烁的效果
        //这里只要在拖动结束的时候。在进行插值Mathf.Lerp,实现回弹效果
        if (!isDrag && posList.Count > 0)
        {
            rect.horizontalNormalizedPosition = Mathf.Lerp(rect.horizontalNormalizedPosition, targethorizontal, Time.deltaTime * smooting);

        }
    }

}

翻页容器中,经常会配对下标显示。这边相应也写了一个代码:

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

/// 
/// @desc:       翻页容器高亮下标。创建一个panel,添加toggle group,添加hor layout group, 在panel添加一个
///              Toggle,并为Toggle添加layout element勾选preferred属性;
/// @author:     Rambo
/// 
public class PageViewMark : MonoBehaviour {
    public ToggleGroup toggleGroup; //图标组
    public Toggle togglePrefab;     //图标
    public PageView pageView;
    public int count = 1;

    private List toggleList = new List();

    /// 
    /// pageview回调
    /// 
    /// 当前page页面下标
    private void OnScrollPageChanged(int currentPageIndex)
    {
        if (currentPageIndex >= 0)
        {
            toggleList[currentPageIndex].isOn = true;
        }
    }

    /// 
    /// 创建图标
    /// 
    /// 
    private Toggle CreateToggle()
    {
        Toggle t = GameObject.Instantiate(togglePrefab);
        t.gameObject.SetActive(true);
        t.transform.SetParent(toggleGroup.transform);
        t.transform.localScale = Vector3.one;
        t.transform.localPosition = Vector3.zero;
        return t;
    }


	// Use this for initialization
	void Start () {
        for (int i = 0; i < count; i++)
        {
            toggleList.Add(CreateToggle());
        }

        pageView.OnPageChanged = OnScrollPageChanged;
        OnScrollPageChanged(0);
	}
	
	// Update is called once per frame
	void Update () {
	
	}
}

你可能感兴趣的:(unity)