zoukankan      html  css  js  c++  java
  • NGUI系列教程十(Scroll View实现触摸滚动相册效果)

      NGUI中提供了两种Scroll View 一种是通过手指或鼠标滑动视图时移动平面物体,另一种则是直接移动摄像机,他们各有各的好处。但是NGUI提供的Scroll View很难实现类似Android 与 IOS 中的Scroll View 滚动相册的那种效果,不过程序猿的力量是伟大无穷的。虽然不能用它提供的API做出来,但是我们可以通过另外的手打巧妙的实现。这篇文章仔细向大家介绍如何实现自制Scroll View实现滚动相册。

            如下图所示

    这是我们的工程页面,程序的实现原理是将相册在Unity3D世界中呈横向队列,摄像机固定的照射在第一个Item相册,当手指发生滑动事件时,计算向左滑动还是向右滑动,此时整体移动相册队列,而摄像机不动。为了让滑动效果更加好看我们需要使用插值计算滑动的时间,使滑动队列不是直接移动过去,而是以一定惯性移动过去。相册下方我们制作一个小白点用来记录当前滑动的位置,在做几个灰色的点表示队列一共的长度,滑动时下方的小白点也会跟随移动,这样就更想高级控件啦。当然小白点与小灰点是要根据item的数量居中显示的喔。这个面板上的4个CardItem就是我们通过historyinit脚本初始化时动态生成赋值的、当界面发生触摸事件时,会整体移动该面板让自对象的相册队列跟随移动。White(Clone)表示白色的小点,gray(Clone)表示灰色的小点,它们的位置是需要根据滑动事件而改变的。

    首先我们来看下,Panel的的脚本historyInit.cs

    using UnityEngine;
    using System.Collections;
    using System.Collections.Generic;
    
    public class historyInit : MonoBehaviour
    {
    
        //相册列表的每一个item
        public GameObject prefab;
        //灰色的小点
        public GameObject prefabhui;
        //白色的小点
        public GameObject prefabbai;
        //另外一个显示面板
        //用来放置灰色、白色小点
        public Transform ponit;
        //白色小点的临时对象
        private GameObject bai;
    
        //链表,用来记录每一个相册中的一些用户信息
        List<UserData> users = new List<UserData>();
        //灰色、白色小点下方的起始位置。
        int start;
    
        void Start()
        {
            //将当前面板对象储存在全局静态变量中
            Globe.ListPanel = gameObject;
            loadSQL();
            initItem();
        }
    
        //以前是读取数据库
        //写例子程序就没必要使用数据库了
        //这里直接写4个死值,当然数量是灵活使用的
    
        void loadSQL()
        {
            //表示一共向U3D世界中添加横向4个相册队列
            for (int i = 0; i < 4; i++)
            {
                //简单的对象储存
                string name = "momo =" + i;
                string age = "26 = " + i;
                string height = "183 =" + i;
                users.Add(new UserData(name, age, height));
            }
    
        }
    
        void initItem()
        {
            //因为下方灰色 白色的小点需要根据相册列表的数量来计算居中显示
            int size = users.Count;
            //乘以16表示计算所有小点加起来的宽度
            int length = (size - 1) * 16;
            //得到下方灰色 白色 小点的居中起始位置
            start = (-length) >> 1;
    
            for (int i = 0; i < size; i++)
            {
                //把每一个相册加入相册列表
                GameObject o = (GameObject)Instantiate(prefab);
                //设置这个对象的父类为 当前面板
                o.transform.parent = transform;
                //设置相对父类的坐标,这些值可根据自己的情况而设定,
                //总之就是设置相册列表中每一个item的坐标,让它们横向的排列下来就行
                o.transform.localPosition = new Vector3(25 + i * 243, -145f, -86f);
                //设置相对父类的缩放
                o.transform.localScale = new Vector3(0.7349999f, 0.66f, 0.7349999f);
    
                //得到每一个user的信息
                UserData data = users[i];
                Move moveScript = o.GetComponent<Move>();
                moveScript.AgeLabel.text = data.age;
                moveScript.HeightLabel.text = data.height;
                moveScript.NameLabel.text = data.name;
                ////遍历每一个相册对象的子组件,
                //UILabel[] label = o.GetComponentsInChildren<UILabel>();
                ////拿到UILabel并且设置它们的数据
                //label[1].text = data.age;   
                //label[2].text = data.height;
                //label[3].text = data.name;
    
                //把每一个灰色小点加入3D世界
                GameObject hui = (GameObject)Instantiate(prefabhui);
                //设置灰色小点的父类为另外一个面板
                hui.transform.parent = ponit;
                //设置每一个灰色小点的位置与缩放,总之让它们居中排列显示在相册列表下方。
                hui.transform.localPosition = new Vector3(start + i * 16, -120f, 0f);
                hui.transform.localScale = new Vector3(8, 8, 1);
    
                //深度 因为是先在屏幕下方绘制4个灰色的小点, 然后在灰色上面绘制白色小点
                //表示当前的窗口ID 所以深度是为了设置白色小点在灰色小点之上绘制
                hui.GetComponent<UISprite>().depth = 0;
            }
    
            //下面的数据是把当前初始化的数据放在一个static类中
            //在Move脚本中就可以根据这里的数据来判断了。
            //滑动列表的长度
            Globe.list_count = size - 1;
            //相册每一项的宽度
            Globe.list_offset = 243;
            //当前滑动的索引
            Globe.list_currentIndex = 0;
            //点击后打开的新游戏场景
            Globe.list_go_name = "LoadScene";
    
            //把白色小点也加载在3D世界中
            bai = (GameObject)Instantiate(prefabbai);
            print(bai);
            //设置它的深度高于 灰色小点,让白色小点显示在灰色小点之上
            bai.GetComponent<UISprite>().depth = 1;
            //设置白色小点的位置
            setBaiPos();
        }
    
        void Update()
        {
            //当用户滑动界面
            //在Update方法中更新
            //当前白色小点的位置
            setBaiPos();
        }
    
        void setBaiPos()
        {
            //Globe.list_currentIndex 就是当前界面的ID
            //根据ID 重新计算白色小点的位置
            bai.transform.parent = ponit;
            bai.transform.localPosition = new Vector3(start + Globe.list_currentIndex * 16, -120f, -10f);
            bai.transform.localScale = new Vector3(8, 8, 1);
    
        }
    }

    该脚本用于相册队列的初始化工作。在这里初始化相册队列的数量,计算完毕让队列以横向线性的排列方式在Unity3D中。

    Prefab:每个相册的预设,我这里每个相册上还会有一些文字的描述,我需要动态的修改它们的内容。大家也可根据自己的情况制作自己的相册item。

    Prefabhui:相册滚动时下方用来记录相册队列总数的灰色小点。

    Prefabbai :相册滚动时下方用来记录当前滚动页面ID的白色小点。

    Point :因为灰色、白色的点不能和相册队列在一个面板之上,否则会跟着相册队列移动而移动,所以这里将灰色白色的点放在两外一个面板之上。

    我们需要监听每一个CardItem的滑动事件,所以肯定要在每一个CardItem预设之上绑定监听事件的脚本,这里是Move.cs,如下图所示。

    因为需要监听触摸滑动事件,所以肯定要绑定Box Collider组件,这个是NGUI的标准用法。

    Move脚本用来监听向左滑动 向右滑动 点击事件。

    触摸的事件全都写在Move.cs脚本中。

    using UnityEngine;
    using System.Collections;
    
    public class Move : MonoBehaviour
    {
    
        //是否触摸
        bool isTouch = false;
        //是否向左滑动
        bool isRight = false;
        //是否向右滑动
        bool isLeft = false;
        //是否正在滑动中
        bool isOnDrag = false;
        public UILabel AgeLabel;
        public UILabel HeightLabel;
        public UILabel NameLabel;
        public UILabel UserLabel;
    
        //滑动中事件
        void OnDrag(Vector2 delta)
        {
            //为了避免事件冲突
            //这里只判断一个滑动的事件
            if (!isTouch)
            {
                if (delta.x > 0.5)
                {
                    //向左滑动
                    isRight = true;
                    isOnDrag = true;
                }
                else if (delta.x < -0.5)
                {
                    //向右滑动
                    isLeft = true;
                    isOnDrag = true;
                }
                isTouch = true;
            }
        }
    
        //滑动后松手调用OnPress事件
        void OnPress()
        {
            //重新计算当前界面的ID
            if (Globe.list_currentIndex < Globe.list_count && isLeft)
            {
                Globe.list_currentIndex++;
            }
    
            if (Globe.list_currentIndex > 0 && isRight)
            {
                Globe.list_currentIndex--;
            }
    
            //表示一次滑动事件结束
            isTouch = false;
            isLeft = false;
            isRight = false;
        }
    
        void Update()
        {
            //这个方法就是本节内容的核心
            //Globe.ListPanel 这个对象是我们在historyInit脚本中得到的,它用来当面相册面板对象使用插值,让面板有惯性的滑动。
    
            //Vector3.Lerp() 这个是一个插值的方法, 参数1 表示开始的位置 参数2 表示结束的位置  参数3 表示一共所用的时间, 在Time.deltaTime * 5 时间以内 Update每一帧中得到插值当前的数值,只到插值结束
    
            //-(Globe.list_currentIndex * Globe.list_offset) 得到当前需要滑动的目标点。
            //请大家仔细看这个方法。
    
            Globe.ListPanel.transform.localPosition = Vector3.Lerp(Globe.ListPanel.transform.localPosition, new Vector3(-(Globe.list_currentIndex * Globe.list_offset), 0, 0), Time.deltaTime * 5);
        }
    
        void OnClick()
        {
            //当点击某个item时进入这里
            if (!isOnDrag)
            {
                //如果不是在拖动中 进入另一个场景
                //Application.LoadLevel(Globe.list_go_name);
            }
            else
            {
                //否则等待用户重新发生触摸事件
                isOnDrag = false;
            }
        }
    }

    还有两个辅助的类,我也贴出来。

    UserData.cs

    using UnityEngine;
    using System.Collections;
    
    public class UserData
    {
        public string name;
        public string age;
        public string height;
        public string hand;
    
        public UserData(string _name, string _age, string _height)
        {
            age = _age;
            height = _height;
            name = _name;
        }
    }

    Globe.cs 这个静态类用来共享记录多个脚本甚至多个场景所需的数据。

    using System.Collections.Generic;
    using UnityEngine;
    public class Globe
    {
        public static GameObject ListPanel;
        public static int list_count;
        public static int list_currentIndex;
        public static int list_offset;
        public static string list_go_name;
    
    }

    参考:http://www.xuanyusong.com/archives/1465

    我的项目:http://pan.ceeger.com/viewfile.php?file_id=1827&file_key=KOdeQf5o

  • 相关阅读:
    WPF自定义控件与样式(13)-自定义窗体Window & 自适应内容大小消息框MessageBox
    WPF自定义控件与样式(12)-缩略图ThumbnailImage /gif动画图/图片列表
    WPF自定义控件与样式(11)-等待/忙/正在加载状态-控件实现
    WPF自定义控件与样式(10)-进度控件ProcessBar自定义样
    WPF自定义控件与样式(9)-树控件TreeView与菜单Menu-ContextMenu
    WPF自定义控件与样式(8)-ComboBox与自定义多选控件MultComboBox
    WPF自定义控件与样式(7)-列表控件DataGrid与ListView自定义样式
    WPF自定义控件与样式(6)-ScrollViewer与ListBox自定义样式
    Windows10通过命令行导出笔记本电池使用信息
    Flutter简易顶部导航
  • 原文地址:https://www.cnblogs.com/martianzone/p/3383698.html
Copyright © 2011-2022 走看看