Unity系列——构建pageView翻页容器
做ui系统的时候,经常会使用到翻页容器。这边自己封装了一个,主要是根据监听滑动,ScrollRect的horizontalNormalizedPosition属性来实现插值。
实现了动态加载page,可以动态创建格子,每个创建有相应的回调,也有翻页的回调。代码:
using UnityEngine;
using UnityEngine.UI;
using UnityEngine.EventSystems;
using System;
using System.Collections;
using System.Collections.Generic;
/// <summary>
/// @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
/// </summary>
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<GameObject> gridList = new List<GameObject>(); //格子翻页的每个格子存储
private List<GameObject> pageList = new List<GameObject>(); //翻页容器存储
private List<float> posList = new List<float>(); //求出每页的临界角,页索引从0开始
/// <summary>
/// 用于返回一个页码,-1说明没有数据,页码从0开始
/// </summary>
public Action<int> OnPageChanged;
/// <summary>
/// 创建小孩的回调,返回的下标从0开始
/// </summary>
public Action<GameObject, int> 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<GameObject>(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 滑动处理
/// <summary>
/// 开始滑动
/// </summary>
/// <param name="eventData"></param>
public void OnBeginDrag(PointerEventData eventData)
{
isDrag = true;
}
/// <summary>
/// 滑动结束
/// </summary>
/// <param name="eventData"></param>
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 创建格子翻页
/// <summary>
/// 根据pos获取格子父节点GameObject
/// </summary>
/// <param name="pos">下标从0开始</param>
/// <returns></returns>
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;
}
/// <summary>
/// 初始格子翻页容器
/// </summary>
/// <param name="gridItem">格子模板</param>
/// <param name="myRow">行</param>
/// <param name="myColumn">列</param>
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<GameObject>(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 创建普通翻页
/// <summary>
/// 初始化普通翻页
/// </summary>
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
/// <summary>
/// 初始化pageview
/// </summary>
/// <param name="defItem">翻页容器模板,构建时必须添加在content下,每次复制添加时是拿模板的父节点</param>
/// <param name="maxPage">翻页容器的总页数</param>
public void InitPage(GameObject defItem, int maxPage)
{
maxPageNum = maxPage;
defPage = defItem;
}
// Use this for initialization
void Start()
{
rect = transform.GetComponent<ScrollRect>();
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;
/// <summary>
/// @desc: 翻页容器高亮下标。创建一个panel,添加toggle group,添加hor layout group, 在panel添加一个
/// Toggle,并为Toggle添加layout element勾选preferred属性;
/// @author: Rambo
/// </summary>
public class PageViewMark : MonoBehaviour {
public ToggleGroup toggleGroup; //图标组
public Toggle togglePrefab; //图标
public PageView pageView;
public int count = 1;
private List<Toggle> toggleList = new List<Toggle>();
/// <summary>
/// pageview回调
/// </summary>
/// <param name="currentPageIndex">当前page页面下标</param>
private void OnScrollPageChanged(int currentPageIndex)
{
if (currentPageIndex >= 0)
{
toggleList[currentPageIndex].isOn = true;
}
}
/// <summary>
/// 创建图标
/// </summary>
/// <returns></returns>
private Toggle CreateToggle()
{
Toggle t = GameObject.Instantiate<Toggle>(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 () {
}
}
声明:该文观点仅代表作者本人,牛骨文系教育信息发布平台,牛骨文仅提供信息存储空间服务。
- 上一篇: 三、向量的加减乘除法
- 下一篇: 【整理】unity3d优化总结篇
