NGUI所见即所得之UIGrid & UITable
By D.S.Qiu
尊重他人的劳动,支持原创,转载请注明出处:http.dsqiu.iteye.com
你是不是对 UIGrid 和 UITable 定位计算方法还模糊不清,那么这篇文章就是你需要的。
NGUI 提供了 Grid 和 Table 组件,支持的参数很少,功能也很鸡肋,完全不能像 CSS 的 Box 模型那样随心所欲的布局,而且使用 UIGrid 和 UITable 的时候经常会相对 UIGrid 和 UITable 挂载的 Transform 出现偏移,之前使用的时候,都是根据经验来规避的。今天打算把UIGrid 和 UITable 的排列规则看下, 才形成此文。
UIGrid 和 UITable 的原理很简单,对子 Transform 的 List 进行排序,然后更加不同的规则进行定位排列(UIGrid 和 UITable 还是有很大不同的)。
排序(Sort)
UIGrid 和 UITable 定义了5种排列方式(其实是3种,None默认不排序即Transform的默认排序,Custom虽然提供virtual 可以重载):
public enum Sorting { None, Alphabetic, Horizontal, Vertical, Custom, }
对应的三种排序方法:集 Alphabetic 按照名字字符串排序,Horizontal 和 Vertical 按照localPosition 进行的排序
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); }
这里说下,虽然提供了Custom方式,第一感觉NGUI的developer考虑很周到,但是提供的确实重载 virtual 函数的方式,D.S.Qiu 觉得这种方式太不好了,为了一个方法就要写一个 子类去重载,个人觉得指定一个委托,扩展起来会更直观,但这一要求开发者一开始就得指定这个 Custom Sort Delegate。
UIGrid定位原理
下面这段代码是 Reposition() 的一部分,原理很简单:根据定义的cellHeight 和cellWidth 来调整子 Transform 的 localPosition。这里还是吐槽下:Reposition() 的代码太多容易了,至少我看到了这段代码在 Reposition 中出现了两次,完全多余,其实就是处理流程就应该是: 先获取所有子 Transform List ,然后对List 排序,最后就是下面这段定位代码了。
for (int i = 0, imax = list.Count; i < imax; ++i) { Transform t = list[i]; if (!NGUITools.GetActive(t.gameObject) && hideInactive) continue; float depth = t.localPosition.z; Vector3 pos = (arrangement == Arrangement.Horizontal) ? new Vector3(cellWidth * x, -cellHeight * y, depth) : new Vector3(cellWidth * y, -cellHeight * x, depth); if (animateSmoothly && Application.isPlaying) { SpringPosition.Begin(t.gameObject, pos, 15f).updateScrollView = true; } else t.localPosition = pos; if (++x >= maxPerLine && maxPerLine > 0) { x = 0; ++y; } }
UITable 定位原理
UITable 的定位方法在 ReositionVaribleSize 中,跟UIGrid 最大不同点是:UIGrid 只根据定义的cellHeight 和 cellWidth 来计算位置,UITable 根据“内容“(UIWidget)来计算位置的。
protected void RepositionVariableSize (List<Transform> children) { float xOffset = 0; float yOffset = 0; int cols = columns > 0 ? children.Count / columns + 1 : 1; int rows = columns > 0 ? columns : children.Count; Bounds[,] bounds = new Bounds[cols, rows]; Bounds[] boundsRows = new Bounds[rows]; Bounds[] boundsCols = new Bounds[cols]; int x = 0; int y = 0; //这个循环计算每行,每列,每个cell 的内容的编辑 Bounds 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; } } x = 0; y = 0; //计算位置 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 += b.min.x - br.min.x + padding.x; //以每列最右边的x值为标准,即保证每列最左边的基准点 if (direction == Direction.Down) { pos.y = -yOffset - b.extents.y - b.center.y; pos.y += (b.max.y - b.min.y - bc.max.y + bc.min.y) * 0.5f - padding.y; } else { pos.y = yOffset + (b.extents.y - b.center.y); pos.y -= (b.max.y - b.min.y - bc.max.y + bc.min.y) * 0.5f - padding.y; } xOffset += br.max.x - br.min.x + padding.x * 2f; t.localPosition = pos; if (++x >= columns && columns > 0) { x = 0; ++y; xOffset = 0f; yOffset += bc.size.y + padding.y * 2f; } } }
这里还是有吐槽:根据 Bounds 的定义 b.extens.x - b.center.x + b.min.x == 0 ,也就是这部完全是没有必要的,看来UIGrid 的 developer,不光代码逻辑不清晰,难道连大脑都是豆腐花做的么。
pos.x = xOffset + b.extents.x - b.center.x; pos.x += b.min.x - br.min.x + padding.x;
类似计算 y 的值也其他更直接方法:
(b.max.y - b.min.y - bc.max.y + bc.min.y) * 0.5f
使用经验
1.UIGrid 没有考虑Bounds ,根据UIGrid 的计算公式可以知道:UIGrid 的第一个元素的 localPosition 的 x 和 y 一定都是 0 ,所以要位置,必须调整UIGrid 的localPosition ,但是实际在有可能调整的是 子对象,然后再 Scene 窗口看是没问题的(注意此时还没有重排),一运行就会出现位置的偏移。
2.UITable 的子组件的 x 总是以 每列最左为 起始基准点的, y 则是每行居中对齐 :(b.max.y - b.min.y - bc.max.y + bc.min.y) * 0.5f 这行代码起始就是计算当前组件和所在行中心点的偏移。
下图是将NGUI 其中一个组件的 sprite 左移了,就出现下面的排列:
虽然 NGUI 提供了 UIGrid 和 UITable ,起始是非常之不完善,几乎做不了什么功能。这里分享两条经验:
1.使用UIGrid时,调整界面的时候让 UIGrid 的 transform 和 其第一个子组件的 transform 相同,这样经过计算之后,位置就是之前调整想要的。或者将 第一个子组件 transform 重置,这样调整UIGrid 的 transform 位置看到的效果就是真实的。
2.使用UITable 让每列元素的左边界都相同,即左对齐。可以看到 NGUI Example 的 Question Log 的 Table 的所有组件(UILable UISprite)的 pivot 都调整为 left 。
总之,就是根据UIGrid 和UITable 的排列原理做相应的调整。
小结:
这篇文章相对于NGUI所见即所得系列其他文章来说,简单很多。最近要做一个界面根据内容自适应,挺复杂的,一堆莫名其妙的问题。之前一直觉得 Unity 的 UI 没有Window MFC 等开发直接拖拽方式那么直观。NGUI 虽然很庞大,但NGUI越来越容易让我吐槽了,可能是对NGUI的家底多少掌握的缘故吧。
很久就听说Unity要出自己的 UI 了,其实D.S.Qiu 也一直有想尝试自己写一点UI的可视化编辑工具(Visual Editor)。昨天不经意看到 Cocos2D 的 UI 编辑器 CocoStudio 感觉很强大,然后顺手google Unity有没有这方面的工具,果然还是发现了 UIToolkit , bitverse RagePixel 和 EWS editor ,也就说 Unity其实也有些 UI 可视化工具的。尤其 bitverse 支持的组件特别丰富,很强大,只可惜没有集成 Batch DrawCall 的功能。
如果您对D.S.Qiu有任何建议或意见可以在文章后面评论,或者发邮件(gd.s.qiu@gmail.com)交流,您的鼓励和支持是我前进的动力,希望能有更多更好的分享。
转载请在文首注明出处:http://dsqiu.iteye.com/blog/2034883
更多精彩请关注D.S.Qiu的博客和微博(ID:静水逐风)
相关推荐
NGUI Next-Gen UI是一款功能强大、灵活性高的UI插件,是当前最新版本的NGUI插件。它可以覆盖Unity的多个版本,包括Unity 5、Unity 2017和Unity 2018等。与其他UI插件相比,NGUI Next-Gen UI具有高效的性能和优秀的...
3.0.6 - NEW: NGUI now has new written documentation. - NEW: NGUI now has an abundance of ...- DEL: UIGrid and UITable no longer have 'repositionNow' member variable. Right-click it to execute it instead.
《NGUI Next-Gen UI 3.9.0:Unity中的高效UI解决方案》 NGUI,全称为Next-Gen User Interface,是一款专为Unity引擎设计的用户界面(UI)系统,其3.9.0版本是针对Unity 5.0及以上版本优化的升级版。在Unity游戏开发...
最新版本的NGUI插件NGUI Next-Gen UI
- 编辑器集成,所见即所得 - 本地化、数据绑定、委托、事件 - 支持所有平台 - 制作进行 1 次绘制调用的 UI - 随附完整的 C# 源代码 - 已广泛优化 - 专门团队支持 2020.1.5 - NEW: You can now specify per-symbol ...
最新版unity3d扩展插件:NGUI Next-Gen UI3.6.0 运行Unity3D,解压后此压缩包,在菜单Assets中选择自定义导入。 如果无法导入时,请检查导入目录中是否存在中文字符。...所见即所得的集成编辑器,支持所有平台。
《NGUI 3.12.1:经典UI框架的最新迭代》 NGUI,全称为Next-Gen UI,是一款广泛应用于Unity3D游戏开发中的用户界面(UI)系统。尽管随着Unity引擎的发展,Unity Technologies推出了官方的UGUI(Unity GUI),但NGUI...
《NGUI Next-Gen UI v3.11.2 (u5)——Unity中的高效UI解决方案》 在Unity游戏开发中,用户界面(UI)的设计与实现是至关重要的环节,它直接影响到玩家的游戏体验。NGUI(Next-Gen UI)是一款专为Unity引擎设计的UI...
NGUI(Next-Gen User Interface)是一款针对Unity游戏引擎的用户界面系统,旨在提供高效、易用且功能丰富的UI解决方案。版本3.5.7是该系统的某个稳定更新,为开发者提供了更多的特性和优化。 在NGUI 3.5.7中,我们...
NGUI是一款广泛应用于Unity引擎的用户界面(UI)系统,为开发者提供了强大的工具来创建复杂的交互式图形界面。NGUI的最新版本是NGUI Next-Gen UI v2.6.1e,它在原有基础上进行了大量的优化和改进,旨在提供更高效、...
《NGUI Next-Gen UI v3.11.4:Unity界面开发的得力助手》 在游戏开发领域,Unity引擎以其强大的功能和易用性备受开发者青睐。而在Unity中,用户界面(UI)的设计与实现是至关重要的一环,它直接影响着玩家的游戏...
NGUI(Next-Gen UI)是Unity早期的一个流行UI系统,用于替代Unity内置的Basic GUI系统,提供更高效、更灵活的UI解决方案。 NGUI的主要特点包括: 1. **性能优化**:NUI使用了基于图元的渲染方式,提高了UI元素的...
在本教程中,我们将深入探讨如何使用NGUI(Next Generation UI)工具包在Unity中创建一个按钮,并且简要介绍如何下载与安装NGUI。NGUI是Unity中一个非常流行的用户界面工具包,它提供了丰富的功能来帮助开发者设计出...
NGUI(Next-Gen UI)是一款专为Unity引擎设计的用户界面系统插件,其版本3.9.2是该插件的一个重要里程碑。这款插件以“Keep It Simple, Stupid”(KISS原则)为核心设计理念,旨在为开发者提供一个高效、易用且功能...
NGUI是Unity3D引擎中一个非常著名的用户界面(UI)插件,它的全称为Next-Gen UI,由Wendy MacGregor开发并维护。在Unity3D的早期版本中,NGUI因其强大的功能和易用性而备受开发者喜爱,为游戏开发提供了丰富的UI解决...
NGUI 是一款强大的用户界面(UI)系统,适用于Unity3D游戏引擎。NGUI 3.11.1是该插件的一个重要版本,专为Unity5进行了优化和更新,旨在提供更高效、更灵活的UI解决方案。在这个版本中,开发者可以期待一系列改进...
- NEW: Added UICamera.first referencing the active NGUI event system. - FIX: Alpha should now work as expected with Linear lighting. - FIX: UICamera.isOverUI should now work properly for all types of ...
软件介绍: NGUI Next-Gen UI v3.5.8最新完整版,本版本需要Unity 3.5.7或者更高版本。NGUI是一款功能强大的UI系统和事件通知框架。所见即所得的集成编辑器,支持所有平台。本资源来源于网络仅供测试。
NGUI(Next-Gen User Interface)是Unity引擎中的一款旧版UI系统,它为开发者提供了创建复杂的用户界面和交互元素的工具。NGUI 3.12.1是该系统的其中一个版本,专为Unity设计,旨在提升游戏和应用的图形界面体验。在...