写在文章开头:我的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<float> posList = new List<float>();//存四张图片的位置(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<ScrollRect>();
        float horizontalLength = rect.content.rect.width - GetComponent<RectTransform>().rect.width;
        var _rectWidth = GetComponent<RectTransform>().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");
        }
    }
}

 

 

Logo

旨在为数千万中国开发者提供一个无缝且高效的云端环境,以支持学习、使用和贡献开源项目。

更多推荐