代码改变世界

UGUI之布局的使用

2015-10-03 23:20  糯米粥  阅读(12732)  评论(4编辑  收藏  举报

unity的LayoutGroup分为三种,

Horizontal Layout Group(水平布局):对象填充总个父物体,水平会填充

Vertical Layout Group(垂直布局):垂直(高度)会填充

Grid Layout Group (网格布局):以表格的形式布局,不会填充父物体

 比如:垂直布局和水平布局效果

 

Grid Layout Group

  如果单纯的时候用滑动效果可以使用Scroll Rect组件即可。但使用布局就要使用布局控件

Grid Layout Group是网格布局,先看看一个效果

其实滑动依然是用的Scroll Rect。这个就不说了。这里主要说布局。

Spacing 表示 cell之间的距离。

Cell表示格子的宽度和和高度

Start Axis 表示布局方式,有横向和纵向


Child Alignment 表示对齐方式。

 

注意Layout Group节点下面的所有cell节点都是不能修改Rect Transform的。因为cell可能下面会放很多图片,这样我们会用个空的gameObject来当父节点。

 

 

 

但你仔细看。会发现。这个不是整块滑动的。比如手机屏幕左右滑动,是滑动区域判断的。没有划过来的时候。会退回去。像这样

 

这里可以根据Scroll Rect组件的normalizedPosition属性来判断。这是一个Vector2坐标。是滑动中XY的值

horizontalNormalizedPosition:水平的值

verticalNormalizedPosition:垂直的值

需要在拖动结束后判断。需要继承

IBeginDragHandler,IEndDragHandler。引用命名空间:using UnityEngine.EventSystems;

具体代码:

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

public class newScroll : MonoBehaviour, IBeginDragHandler, IEndDragHandler
{
    ScrollRect rect;

    //页面:0,1,2  索引从0开始
    //每夜占的比列:0/2=0  1/2=0.5  2/2=1
    float[] page = { 0, 0.5f, 1 };

    //滑动速度
    public float smooting = 4;

    //滑动的起始坐标
    float targethorizontal = 0;

    //是否拖拽结束
    bool isDrag = false;

    // Use this for initialization
    void Start()
    {
        rect = transform.GetComponent<ScrollRect>();
    }

    // Update is called once per frame
    void Update()
    {
        //如果不判断。当在拖拽的时候要也会执行插值,所以会出现闪烁的效果
        //这里只要在拖动结束的时候。在进行插值
        if (!isDrag)
        {
            rect.horizontalNormalizedPosition = Mathf.Lerp(rect.horizontalNormalizedPosition, targethorizontal, Time.deltaTime * smooting);
        }
    }

    /// <summary>
    /// 拖动开始
    /// </summary>
    /// <param name="eventData"></param>
    public void OnBeginDrag(PointerEventData eventData)
    {
        isDrag = true;
    }

    /// <summary>
    /// 拖拽结束
    /// </summary>
    /// <param name="eventData"></param>
    public void OnEndDrag(PointerEventData eventData)
    {
        isDrag = false;

        //    //拖动停止滑动的坐标 
        //    Vector2 f = rect.normalizedPosition;
        //    //水平  开始值是0  结尾值是1  [0,1]
        //    float h = rect.horizontalNormalizedPosition;
        //    //垂直
        //    float v = rect.verticalNormalizedPosition;




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

                //保存当前的偏移量
                //如果到最后一页。反翻页。所以要保存该值,如果不保存。你试试效果就知道
                offset = temp;
            }
        }

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


        targethorizontal = page[index];
    }
}

 

像这种布局。内容是动态添加的。所以内容的多少是不确定的。很多时候是用u3d自带的ContentSizeFitter。这个组件可以自动计算宽度

 

那么问题来了。当总数不是页数的倍数,那么horizontalNormalizedPosition是不正确的。比如:有2页。一页5条

当只有6条。是不是也是2页呢?。

所以又得必须动态计算了。

这里写了一个适用于其他场合的类

  1 using System;
  2 using System.Collections.Generic;
  3 using System.Linq;
  4 using System.Text;
  5 using UnityEngine;
  6 using UnityEngine.EventSystems;
  7 using UnityEngine.UI;
  8 
  9 class UIScrollItemTips : MonoBehaviour, IBeginDragHandler, IEndDragHandler
 10 {
 11     //页面:0,1,2  索引从0开始
 12     //每夜占的比列:0/2=0  1/2=0.5  2/2=1
 13     public List<float> pageArray;
 14 
 15     //public List<float> PageArray
 16     //{
 17     //    // get { return pageArray; }
 18     //    set { pageArray = value; }
 19     //}
 20     private List<Toggle> toggleArray;
 21 
 22     public List<Toggle> ToggleArray
 23     {
 24         //get { return toggleArray; }
 25         set { toggleArray = value; }
 26     }
 27     public int pageCount;//多少页
 28 
 29     public int pageIndex = 0;//:当前页码
 30     private ScrollRect rect;
 31     //滑动速度
 32     public float smooting;
 33 
 34     public float Smooting
 35     {
 36         get { return smooting; }
 37         set { smooting = value; }
 38     }
 39 
 40     private int pageSize;
 41 
 42     /// <summary>
 43     /// 一页显示多少条
 44     /// </summary>
 45     public int setPageSize
 46     {
 47         get { return pageSize; }
 48         set { pageSize = value; }
 49     }
 50 
 51     private int sumRecord;
 52 
 53     /// <summary>
 54     /// 总记录数
 55     /// </summary>
 56     public int setSumRecord
 57     {
 58         get { return sumRecord; }
 59         set { sumRecord = value; }
 60     }
 61 
 62     private List<GameObject> pageList = new List<GameObject>();
 63 
 64     //滑动的起始坐标
 65     public float targethorizontal = 0;
 66 
 67     //是否拖拽结束
 68     public bool isDrag = false;
 69 
 70 
 71     public GameObject root;
 72 
 73     private int updateInfo;
 74 
 75     public int UpdateInfo
 76     {
 77         //get { return updateInof; }
 78         set { Init(); }
 79     }
 80 
 81     //private static UIScrollItem instance;
 82     //public static UIScrollItem Instance
 83     //{
 84     //    get { return instance; }
 85     //    //set { ObjectPools.instance = value; }
 86     //}
 87 
 88     void Init()
 89     {
 90         UnInit();
 91         //pageSize = 8;
 92         //setSumRecord = 54;
 93         smooting = 4;
 94         rect = transform.GetComponent<ScrollRect>();
 95         pageArray = new List<float>();
 96         toggleArray = new List<Toggle>();
 97         targethorizontal = 0;
 98         rect.horizontalNormalizedPosition = 0;
 99         //instance = this; //单列
100 
101         pageCount = Convert.ToInt32(Math.Ceiling((double)sumRecord / pageSize)); //sumRecord为总记录数
102 
103         //Debug.LogError(pageCount);
104 
105         //求出每页的临界角,页索引从0开始
106         int num = pageCount - 1;
107         if (num == 0) num = 1;
108         for (int i = 0; i < pageCount; i++)
109         {
110             //Debug.LogError(i + "/" + num + "==" + (float)i / (float)num);
111             pageArray.Add((float)i / (float)num);
112         }
113 
114         if (root != null)
115         {
116             ToggleGroup group = root.GetComponent<ToggleGroup>();
117 
118             for (int i = 0; i < pageCount; i++)
119             {
120                 //获取页码预设体
121                 GameObject pageItem = U3DResources.SpawnUI("Item_New");
122                 pageList.Add(pageItem);
123                 pageItem.transform.SetParent(root.transform);
124                 pageItem.transform.localScale = new Vector3(1, 1, 1);
125                 pageItem.transform.localRotation = new Quaternion();
126                 pageItem.transform.localPosition = Vector3.one;
127 
128                 Toggle toogle = pageItem.transform.Find("page").GetComponent<Toggle>();
129                 toogle.group = group;
130                 toggleArray.Add(toogle);
131             }
132 
133 
134         }
135 
136         //Debug.LogError(pageSize);
137 
138         //rect.horizontalNormalizedPosition = 0;
139 
140         //不管怎样默认都是显示最后一页,同理,页码页码也是。已在生成页码时处理
141         //初始化不需要显示滑动效果。直接赋值即可
142         //targethorizontal = pageArray[pageArray.Count - 1];
143         //rect.horizontalNormalizedPosition = pageArray[pageArray.Count - 1];
144 
145         foreach (var item in toggleArray)
146         {
147             item.isOn = false;
148         }
149 
150         if (toggleArray.Count > 0)
151         {
152             //默认第一个选中
153             toggleArray[0].isOn = true;
154 
155         }
156     }
157 
158     void Awake()
159     {
160     }
161     void Start()
162     {
163         //Init();
164         //rect.horizontalNormalizedPosition = 0;
165     }
166 
167     void Update()
168     {
169         //如果不判断。当在拖拽的时候要也会执行插值,所以会出现闪烁的效果
170         ////这里只要在拖动结束的时候。在进行插值
171         if (!isDrag)
172         {
173             rect.horizontalNormalizedPosition = Mathf.Lerp(rect.horizontalNormalizedPosition, targethorizontal, Time.deltaTime * smooting);
174 
175             //rect.horizontalNormalizedPosition = targethorizontal;
176         }
177     }
178     /// <summary>
179     /// 拖动开始
180     /// </summary>
181     /// <param name="eventData"></param>
182     public void OnBeginDrag(PointerEventData eventData)
183     {
184         isDrag = true;
185     }
186 
187     /// <summary>
188     /// 拖拽结束
189     /// </summary>
190     /// <param name="eventData"></param>
191     public void OnEndDrag(PointerEventData eventData)
192     {
193         isDrag = false;
194 
195         float posX = rect.horizontalNormalizedPosition;
196         int index = 0;
197         //假设离第一位最近
198         float offset = Mathf.Abs(pageArray[index] - posX);
199         for (int i = 1; i < pageArray.Count; i++)
200         {
201             float temp = Mathf.Abs(pageArray[i] - posX);
202             if (temp < offset)
203             {
204                 index = i;
205                 //保存当前的偏移量
206                 offset = temp;
207             }
208         }
209         try
210         {
211             targethorizontal = pageArray[index];
212             //说明页码大于1 toggle有值
213             if (pageCount > 1 && toggleArray.Count > 0)
214                 toggleArray[index].isOn = true;
215         }
216         catch (Exception)
217         {
218             return;
219         }
220     }
221 
222     void UnInit()
223     {
224         foreach (var item in pageList)
225         {
226             U3DResources.Despawn(item);
227         }
228     }
229 }
View Code

调用

 1 itemTips.setSumRecord = nows;
 2             itemTips.setPageSize = 8;
 3             mItemGrid.GetComponent<ContentSizeFitter>().enabled = false;
 4 
 5             //总页数
 6             int pageCount = Convert.ToInt32(Math.Ceiling((double)nows / itemTips.setPageSize)); //sumRecord为总记录数
 7 
 8             int resultCount = nows;
 9 
10             if (nows % itemTips.setPageSize != 0)
11             {
12                 //求差
13                 int poor = pageCount * itemTips.setPageSize - nows;
14                 //加上差数。凑整
15                 resultCount = nows + poor;
16             }
17             else
18             {
19                 //可以启用自动计算宽度
20                 //mItemGrid.GetComponent<ContentSizeFitter>().enabled = true;
21             }
22 
23             //Debug.LogError(nows);
24             //Debug.LogError(resultCount);
25 
26             GridLayoutGroup group = mItemGrid.GetComponent<GridLayoutGroup>();
27             float cellSize = group.cellSize.x; //一个格子的宽度
28             float spacing = group.spacing.x; //格子的间距
29 
30             //总宽度
31             float totalWidth = cellSize * resultCount + (resultCount - 1) * spacing;
32             //Debug.LogError(totalWidth);
33 
34             RectTransform rectWidth = mItemGrid.GetComponent<RectTransform>();
35             Vector2 targetVec = new Vector2(totalWidth, rectWidth.sizeDelta.y);
36             rectWidth.sizeDelta = targetVec;
View Code

itemTips是UIScrollItemTips变量

ScrollRect滑动组件。怎么可以定位到哪个地方呢。即滑动到指定位置;

ScrollRect有个属性normalizedPosition,是Vector2类型的。

如果是垂直滑动;那么范围是1-0

比如到初始位置

GetComponent<ScrollRect>().normalizedPosition = new Vector2(0, 1);

滑动到最后一页

GetComponent<ScrollRect>().normalizedPosition = new Vector2(0, 0);