NGUI布局組件:UIGrid /UITable


一、UIGrid:排列等比大小子對象。
Reposition:排列方法。
  1. 觸發:MonoBehaviour的Start、設置repositionNow= true或者手動調用。
  1. 獲取並排列子對象:GetChildList,排序方法也很簡單。
public List<Transform> GetChildList ()
{
   Transform myTrans = transform;
   List<Transform> list = new List<Transform>();
 
   for (int i = 0; i < myTrans.childCount; ++i)
   {
      Transform t = myTrans.GetChild(i);
 
      if (!hideInactive || (t && t.gameObject.activeSelf))
      {
         if (!UIDragDropItem.IsDragged(t.gameObject)) list.Add(t);
      }
   }
 
   // Sort the list using the desired sorting logic
   if (sorting != Sorting.None && arrangement != Arrangement.CellSnap)
   {
      if (sorting == Sorting.Alphabetic) list.Sort(SortByName);
      else if (sorting == Sorting.Horizontal) list.Sort(SortHorizontal);
      else if (sorting == Sorting.Vertical) list.Sort(SortVertical);
      else if (onCustomSort != null) list.Sort(onCustomSort);
      else Sort(list);
   }
   return list;
}
 
static public int SortByName (Transform a, Transform b) { return string.Compare(a.name, b.name); }
static public int SortHorizontal (Transform a, Transform b) { return a.localPosition.x.CompareTo(b.localPosition.x); }
static public int SortVertical (Transform a, Transform b) { return b.localPosition.y.CompareTo(a.localPosition.y); }
  1. 按左上角為起始點排序子節點。
int x = 0;
int y = 0;
int maxX = 0;
int maxY = 0;
 
// Re-add the children in the same order we have them in and position them accordingly
for (int i = 0, imax = list.Count; i < imax; ++i)
{
   Transform t = list[i];
   Vector3 pos = t.localPosition;
   float depth = pos.z;
 
   if (arrangement == Arrangement.CellSnap)
   {
      if (cellWidth > 0) pos.x = Mathf.Round(pos.x / cellWidth) * cellWidth;
      if (cellHeight > 0) pos.y = Mathf.Round(pos.y / cellHeight) * cellHeight;
   }
   else pos = (arrangement == Arrangement.Horizontal) ?
      new Vector3(cellWidth * x, -cellHeight * y, depth) : //橫向排序,x軸遞增cellWidth
      new Vector3(cellWidth * y, -cellHeight * x, depth); //縱向排序,y軸遞減cellHeight
 
   if (animateSmoothly && Application.isPlaying && (pivot != UIWidget.Pivot.TopLeft || Vector3.SqrMagnitude(t.localPosition - pos) >= 0.0001f))
   {
      var sp = SpringPosition.Begin(t.gameObject, pos, 15f);
      sp.updateScrollView = true;
      sp.ignoreTimeScale = true;
   }
   else t.localPosition = pos;
 
   maxX = Mathf.Max(maxX, x);//最大列數
   maxY = Mathf.Max(maxY, y);//最大行數
 
   if (++x >= maxPerLine && maxPerLine > 0) //換行
   {
      x = 0;
      ++y;
   }
}
  • 執行結果如下:
  1. 通過pivot調整相對與父節點的坐標,因為父節點坐標不變,實際是變相整體位移了所有子節點。
  • 上圖的po是(0,0),下圖是(0.5, 0.5)。
if (pivot != UIWidget.Pivot.TopLeft)
{
   var po = NGUIMath.GetPivotOffset(pivot);
 
   float fx, fy;
 
   if (arrangement == Arrangement.Horizontal)
   {
      fx = Mathf.Lerp(0f, maxX * cellWidth, po.x);
      fy = Mathf.Lerp(-maxY * cellHeight, 0f, po.y);
   }
   else
   {
      fx = Mathf.Lerp(0f, maxY * cellWidth, po.x);
      fy = Mathf.Lerp(-maxX * cellHeight, 0f, po.y);
   }
 
   foreach (var t in list)
   {
      Vector3 pos = t.localPosition;
         pos.x -= fx;
         pos.y -= fy;
         t.localPosition = pos;
   }
}
 
二、UITable:排列不同大小的子對象,會計算子節點的包圍盒。
Reposition:排列方法。
  1. 觸發:MonoBehaviour的Start、設置repositionNow= true(在lateUpdate執行,也就是當前幀結束時)或者手動調用。
  1. 獲取並排列子對象:GetChildList,排序方法調的是UIGrid的接口。
  1. 子節點、每行、每列的包圍盒計算,注意這邊的包圍盒center都是(0,0),第y行的的包圍盒boundsCols[y]實際上是center(0,0),extents.x = 改行節點最大的寬/2,extents.y = 改行節點最大的高/2。bounds[y, x]一定是包含在范圍更大的boundsRows[x]、boundsCols[y]內,且中心點都在(0,0)點。
for (int i = 0, imax = children.Count; i < imax; ++i)
{
   Transform t = children[i];
   Bounds b = NGUIMath.CalculateRelativeWidgetBounds(t, !hideInactive);
 
   Vector3 scale = t.localScale;
   b.min = Vector3.Scale(b.min, scale);
   b.max = Vector3.Scale(b.max, scale);
   bounds[y, x] = b;
 
   boundsRows[x].Encapsulate(b);
   boundsCols[y].Encapsulate(b);
 
   if (++x >= columns && columns > 0)
   {
      x = 0;
      ++y;
   }
}
  • 如上圖,b.size=b.extents*2,min = -b.extents,max = b.extents.
  1. 以左上角為基點,排列子節點。看注釋段比較好理解。
Vector2 po = NGUIMath.GetPivotOffset(cellAlignment);
 
for (int i = 0, imax = children.Count; i < imax; ++i)
{
   Transform t = children[i];
   Bounds b = bounds[y, x];
   Bounds br = boundsRows[x];
   Bounds bc = boundsCols[y];
 
   Vector3 pos = t.localPosition;
   pos.x = xOffset + b.extents.x - b.center.x;
   pos.x -= Mathf.Lerp(0f, b.max.x - b.min.x - br.max.x + br.min.x, po.x) - padding.x;
 
   //pos.x = xOffset + b.extents.x;//x現在在左邊界
   //float maxDis = (br.max.x - br.min.x) - (b.max.x - b.min.x);
   //loat offsetX  = Mathf.Lerp(0f, maxDis, po.x) ;//計算最終要偏移的距離
   //pos.x += offsetX  +  padding.x;
 
   if (direction == Direction.Down)
   {
      pos.y = -yOffset - b.extents.y - b.center.y;
      pos.y += Mathf.Lerp(b.max.y - b.min.y - bc.max.y + bc.min.y, 0f, po.y) - padding.y;
   }
   else
   {
      pos.y = yOffset + b.extents.y - b.center.y;
      pos.y -= Mathf.Lerp(0f, b.max.y - b.min.y - bc.max.y + bc.min.y, po.y) - padding.y;
   }
 
   xOffset += br.size.x + padding.x * 2f;
 
   t.localPosition = pos;
 
   if (++x >= columns && columns > 0)
   {
      x = 0;
      ++y;
 
      xOffset = 0f;
      yOffset += bc.size.y + padding.y * 2f;
   }
}
  • 先把子節點放在當前列br的左邊界。pos.x = xOffset + b.extents.x;
  • 計算從左邊界移到當前列br有邊界的距離。float maxDis = (br.max.x - br.min.x) - (b.max.x - b.min.x);
  • 通過cellAlignment計算最終要偏移的距離。float offsetX  = Mathf.Lerp(0f, maxDis, po.x) ;
  • 修正pos。pos.x += offsetX  +  padding.x
左上角對齊:
右下對齊:
  1. 通過pivot調整相對與父節點的坐標,因為父節點坐標不變,實際是變相修改了子節點的坐標。同UIGride.


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM