写在文章开头:我的unity版本是2018.3,写这个的目的是为了刚刚接触unity的小白(就是我),因为项目中使用Cocos的PageView做了公告系统,最近在自学unity,所以想着用unity怎么实现。翻了很多博客,感觉对我这样的小白很不友好,自己边参考边摸索着实现了这个功能,就想写下来,希望能帮助到其他小白。
模仿大佬放一下github地址:https://github.com/liushuang620/Unity_ScrollView
利用ScrollView实现多个页面滑动切换的功能,具体实现效果如下gif
1. 工程面板中添加ScrollView,可以把ScrollBar子对象删除, content大小设置成可容纳四张图片,并在content下添加4个image子对象,整个工程完整目录如下图
2. ScrollView下添加PageView子组件
3.添加空对象GameObject,命名为GameController,给它挂载GameControler脚本(Button关联响应函数的话,相关脚本必须挂载在当前场景中的某个物体上)
4. 添加InputField和Button, InputField的子对象Placeholder中的Text文本改为“请输入页码...”,Button关联GameController下的OnButtonDown函数
5.创建一个空物体GameObject,给它添加ToggleGroup组件,空物体下添加Text和4个Toggle子对象,具体结构参考第一张工程结构总图,为每一个Toggle对象绑定OnValueChange事件,可参考下图
注:为Toggle有两种绑定事件的方式具体见文章番外:)
ToggleGroup的作用:开关组,简单点儿说,开关组的作用就是在这组开关中,只能有一个开关处于true的状态,详细说明可参考以下链接
https://blog.csdn.net/qq992817263/article/details/51754442
====================工程说完了接下来是代码了=============================
PageView脚本:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
using UnityEngine.EventSystems;
using System;
public class PageView : MonoBehaviour, IBeginDragHandler, IEndDragHandler
{
private ScrollRect rect;
private float targethorizontal = 0;
private List posList = new List();//存四张图片的位置(0, 0.333, 0.666, 1)
private bool isDrag = true;
private float startTime = 0;
private float startDragHorizontal;
private int curIndex = 0;
public float speed = 4; //滑动速度
public float sensitivity = 0;
public Toggle[] toggleArray; //toggle开关
public Text curPage;
void Start()
{
rect = GetComponent();
float horizontalLength = rect.content.rect.width - GetComponent().rect.width;
var _rectWidth = GetComponent().rect.width;
for (int i = 0; i < rect.content.transform.childCount; i++)
{
posList.Add(_rectWidth * i / horizontalLength); //存四张图片的位置(0, 0.333, 0.666, 1)
}
curIndex = 0;
toggleArray[0].isOn = true;
curPage.text = String.Format("当前页码:0");
}
void Update()
{
if (!isDrag)
{
startTime += Time.deltaTime;
float t = startTime * speed;
rect.horizontalNormalizedPosition = Mathf.Lerp(rect.horizontalNormalizedPosition, targethorizontal, t); //加速滑动效果
//rect.horizontalNormalizedPosition = Mathf.Lerp(rect.horizontalNormalizedPosition, targethorizontal, Time.deltaTime * speed); //缓慢匀速滑动效果
}
}
public void OnBeginDrag(PointerEventData eventData)
{
isDrag = true;
//开始拖动
startDragHorizontal = rect.horizontalNormalizedPosition; //horizontalNormalizedPosition这个参数是scrollRect滑动期间变化的x坐标值,在(0, 1)之间
}
public void OnEndDrag(PointerEventData eventData)
{
Debug.Log("OnEndDrag");
float posX = rect.horizontalNormalizedPosition;
int index = 0;
float offset = Mathf.Abs(posList[index] - posX); //计算当前位置与第一页的偏移量,初始化offect
for (int i = 1; i < posList.Count; i++)
{ //遍历页签,选取当前x位置和每页偏移量最小的那个页面
float temp = Mathf.Abs(posList[i] - posX);
if (temp < offset)
{
index = i;
offset = temp;
}
}
curIndex = index;
targethorizontal = posList[curIndex]; //设置当前坐标,更新函数进行插值
isDrag = false;
startTime = 0;
toggleArray[curIndex].isOn = true; //因为使用了ToggleGroup,所以这里只把要显示的页面置true即可,其他Toggle会自己改为false(这个是我踩过的坑)
curPage.text = String.Format("当前页码:{0}", curIndex.ToString());
}
public void pageTo(int index)
{
Debug.Log("pageTo......");
curIndex = index;
targethorizontal = posList[curIndex]; //设置当前坐标,更新函数进行插值
isDrag = false;
startTime = 0;
toggleArray[curIndex].isOn = true;
curPage.text = String.Format("当前页码:{0}", curIndex.ToString());
}
}
GameController脚本:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
using UnityEngine.EventSystems;
public class GameController : MonoBehaviour
{
public InputField inputField;
public PageView pageView;
//public Toggle toggle0; //代码动态添加监听方法,无需在界面指定,如果使用这种方法就不要在界面再绑定一次了
//public Toggle toggle1;
//public Toggle toggle2;
//public Toggle toggle3;
private void Start()
{
//代码动态添加监听方法,无需在界面指定
//toggle0.onValueChanged.AddListener(OnValueChanged0);
//toggle1.onValueChanged.AddListener(OnValueChanged1);
//toggle2.onValueChanged.AddListener(OnValueChanged2);
//toggle3.onValueChanged.AddListener(OnValueChanged3);
}
public void OnButtonDown()
{
int index = int.Parse(inputField.text);
pageView.pageTo(index);
}
public void OnValueChanged0(bool check)
{
Debug.Log("OnValueChanged0");
if (check)
{
Debug.Log("Page to 0");
pageView.pageTo(0);
}
else
{
Debug.Log("Toggle0 isOn false");
}
}
public void OnValueChanged1(bool check)
{
Debug.Log("OnValueChanged1");
if (check)
{
Debug.Log("Page to 1");
pageView.pageTo(1);
}
else
{
Debug.Log("Toggle1 isOn false");
}
}
public void OnValueChanged2(bool check)
{
Debug.Log("OnValueChanged2");
if (check)
{
Debug.Log("Page to 2");
pageView.pageTo(2);
}
else
{
Debug.Log("Toggle2 isOn false");
}
}
public void OnValueChanged3(bool check)
{
Debug.Log("OnValueChanged3");
if (check)
{
Debug.Log("Page to 3");
pageView.pageTo(3);
}
else
{
Debug.Log("Toggle0 isOn false");
}
}
}
==============================这里是番外=========================================
Toggle--onValueChanged: isOn的值改变的时候调用,有两种绑定事件的方式,一种是在unity编辑器inspector界面自己手动绑定事件,如下图
另外一种是在代码里动态绑定,代码如下
public class GameController : MonoBehaviour
{
public Toggle toggle0; //代码动态添加监听方法,无需在界面指定
private void Start()
{
//代码动态添加监听方法,无需在界面指定
toggle0.onValueChanged.AddListener(OnValueChanged0);
}
public void OnValueChanged0(bool check)
{
Debug.Log("OnValueChanged0");
if (check)
{
Debug.Log("Page to 0");
pageView.pageTo(0);
}
else
{
Debug.Log("Toggle0 isOn false");
}
}
}