本文仅仅记录自己在工作中踩到的ugui的坑。并讲述如何填的坑。

干货罗列在前,不愿意看的,拿东西走人,自己研究:

  • RectTransform m_Rect
  • m_Rect.localPosition
  • m_Rect.rect  (m_Rect.rect.width  m_Rect.rect.height)
  • m_Rect.pivot
  • m_Rect.sizeDelta

关于ugui的排版方面,刚上手的时候,觉得:哎哟!不错,这个刁。

但是如果你使用过qt等软件,其实ugui的对齐功能还是很落后的。

如果你继续使用这个排版功能,你就会发现:什么啊这是,什么逻辑啊,完全没懂啊。

关于ugui工作的原理以及各个参数不在本文讨论范围之内。什么这个参数改一下会如何,原点等,一概不研究,只说两件事:

  1. 如何修改ugui控件到我指定的大小
  2. 如何移动ugui到指定位置上去

关于ugui的以上两点,都在RectTransform这个组件里。而这个组件的变量虽然并不很多,但是互相关联非常精密。如果没有弄懂ugui是如何设计的,几乎没办法随心所欲的工作。

这里说的随心所欲的工作指的是:当我想要移动或者缩放ugui控件的时候,能够直接修改变量成我期望的值,或者传入参数就能达到我期望的效果。

比方说。我期望控件移动到跟另外一个控件相同的位置上去(对齐)。或者我希望A控件改变大小和B一样。又或者跟随鼠标移动。

以上三个情况,如果你摆弄过ugui,其实就很容易暴露RectTransform里面的问题。

以下,用我的工作作为讲解。告诉你如何通过简单的技巧,让你跳过理解ugui排版直接实现最简单的移动和缩放。让排版功能化繁为简,返璞归真

先说一些基本的内容。

  1. Position和localPosition值不一样,而且没有找出规律,在我测试到的范围内,position这个变量几乎不能用于脚本的各种计算。
  2. ugui在控件位置不发生变化的情况下,修改pivot,Position和localPosition会变。
  3. pivot这个变量,在unity面板里修改和在脚本里修改表现出的行为不一致。
    1. 在unity面板里修改,表现出的行为是ugui空间在屏幕上的位置没有发生变化,而Position和localPosition有改变;
    2. 在脚本里修改pivot,Position和localPosition不会改变,而ugui空间在屏幕上的位置会改变
  4. rect只读,整个结构下面的所有数据仅仅是只读,没找到方法修改。但是rect的widht和height属性记录的是ugui控件的像素大小(缩放是否参与影响暂时还没进展到这步)
  5. 可以通过sizeDelta修改ugui控件大小。但是这个变量和ugui自身的对齐方式有关(锚点位置和方式),如果你没有弄懂对齐方式跟sizeDelta的关系,只是简单的将sizeDelta改成(100.0f,100.0f)出现的大小可能不会是100×100.

有了以上基本内容,就可以开始讲解了。

我要做一个镶嵌。将B镶嵌到A的Slot里去。Slot有背景图,图片初始很小,镶嵌物大小不一,所以当镶嵌完成,背景图需要缩放。B需要修改坐标和A的Slot相同。

先说缩放。

会影响缩放的,主要是anchor参数。这个参数在不同值的时候,对缩放的影响是不一样的。因为Slot有上有下,有些靠左,有些靠右,有些居中,所以anchor参数各式各样。

思路其实很简单。因为在scanl都为1的状态下(别的状态还没测试),rect的widht和height属性就是控件的大小。所以将B的大小直接给Slot即可。

于是将sizeDelta修改为widht和height的值。完成。

最开始的时候所有slot的锚点都是在左上角,该方案还行。可是后面出现了各种随父控件大小变化以及锚点左中右对齐的slot之后,这个方案就失效了,将B的widht和height直接给slot,出现了各种奇怪的大小。

这才发现收anchor变量和offsetmax/min这些变量影响。

调试了很久,输出sizeDelta信息查看之后才发现,虽然sizeDelta的值很难理解,但是sizeDelta的增量却是正确的。比方说,我将sizeDelta改成100×100和200×200大小我是确定不了。但是从100到200,sizeDelta的输出信息可以看到增量了100。

于是逐将上面的方案改为:

sizeDelta+增量即可。

代码片段

         RectTransform mNewNodeRect = newNode.GetComponent<RectTransform>();
RectTransform mSlotRect = mSlot.GetComponent<RectTransform>();
float mX = mNewNodeRect.rect.width - mSlotRect.rect.width;
float mY = mNewNodeRect.rect.height - mSlotRect.rect.height;
mSlotRect.sizeDelta = new Vector2(mSlotRect.sizeDelta.x + mX, mSlotRect.sizeDelta.y + mY);

至此,缩放搞定。你不需要知道任何ugui对齐相关的东西,就可以实现准确的缩放。

然后是移动。

最开始做的时候,因为锚点全都在左上角。所以移动的时候很简单,直接在面板里修改PosX和PosY就好。

但是因为PosX和Posy受pivot影响,所以输出查看坐标数据,发现Position和LocalPosition两个变量,LocalPosition变量的值是PosX和PosY里的数据,于是采用了LocalPosition。

于是镶嵌方案就是:

先将slot拉到B的大小,然后再将slot的位置给B。

因为从外部保证了界面制作的时候,锚点和pivot全部一样,所以这个方案成功用了一段时间。

后来,随着各种其他方式的锚点的加入,又有不同的pivot的加入。原本的坐标直接给值的方案就不行了。于是又测试。

这次测试发现,ui控件坐标,是以pivot点为原点。如果你将两个不同对齐方式的ugui控件设置成一样的LocalPosition(父控件相同的前提下),那么对齐的点,是pivot点。

因为我的slot背景图已经拉伸到和B一样大了。所以我需要的是让两个控件的图片左上对齐。

而pivot是一个0~1的值。0,就在最左上,1就在右下。正好是宽高。所以widht*pivot.x正好就是左边到pivot的距离。

于是修改方案就出来了。

         Vector3 mLeftTop = m_Rect.localPosition;
float mLeftOffset = m_Rect.rect.width * m_Rect.pivot.x;
float mTopOffset = m_Rect.rect.height * m_Rect.pivot.y;
mLeftTop.x -= mLeftOffset;
mLeftTop.y -= mTopOffset; RectTransform mInsert = m_Insert.GetComponent<RectTransform>();
mLeftOffset = mInsert.rect.width * mInsert.pivot.x;
mTopOffset = mInsert.rect.height * mInsert.pivot.y;
Vector3 mfinalyPos = mLeftTop + new Vector3(mLeftOffset, mTopOffset, 0.0f);
mInsert.localPosition = mfinalyPos;

原理就是,先计算出slot的左上角的点。然后再将B设置到这个点上,然后B再自己加上从左上点到pivot点的差值。就可以让两图以左上角对齐了(其他对齐方式自行推演)。

一个sizeDelta,一个localPosition就可以跳过复杂的ugui的锚定实现正确的对齐和缩放。

至此,ugui的缩放和移动就大功告成。

这里不得不谈下自己的感想:

我们做东西的时候,都是习惯先按照自己的思维和理解来做。如果符合自己的思维,则好用。不符合,“这tm什么设计,脑子有屎”。用这样的观点来做事,不太好。一是不尊重别人的劳动成果。二是学习东西始终带抵触情绪。

虽然我知道我应该去学习和满足unity的设计要求。但是这样的ugui设计,真的是脑子有屎。强大到只有程序才会懂的ui,你做鸟的编辑界面啊。直接给程序说明文档就好了。想做个ui上最常见的移动和缩放,我还得先研究一下ui系统怎么设计的。而且最终出来的效果是既不方便使用,也不方便理解,也赶不上别的ui系统(有用过qt做编程的就会懂得qt的编辑器和ui对齐方式多么直观)。我只想说:这tm什么设计,脑子有屎。

这个ugui,一点都不符合unity的风格。

--------------------------------------------------

特别补充一点,以上方案,是在A是父对象,slot和B同级目录下,scan为1的情况下进行的,不同目录情况,请自信根据文中线索推导。另外缩放系数参与的情况下未进行测试

------------------------2016 09 26 11:33--------------------------

在已经有以上知识内容的前提下,修正一个bug。

因为pivot这个变量是用于铆钉控件自身的对齐方式。举例:如果我把坐标填写成0.0.0点。空间将会用pivot的点去对。而pivot是以左下角为0.0,所以如果pivot为0.0的时候,你会看到控件以左下角为对齐点去对0.0.0点坐标。

提这个的原因是因为,获取到A的坐标之后,其实是获取的A的pivot点。需要通过修正来满足自己的需求。本文上面的

float mLeftOffset = m_Rect.rect.width * m_Rect.pivot.x;
float mTopOffset = m_Rect.rect.height * m_Rect.pivot.y;
mLeftTop.x -= mLeftOffset;
mLeftTop.y -= mTopOffset;

这段修正代码,是在计算左下点的坐标,而不是左上。

提到这里我觉得就够了,坐标点算偏移不是难事,各位自己算下自己期望的坐标偏移就好。我也要自己检查下为什么之前用这个算法算出来竟然是期望的左上。

------------------------2016 09 26 19:01--------------------------

好吧,我查了下我自己的bug,我这个算法,其实是左下角对齐的方式。但是呢,因为我的镶嵌背景和镶嵌物等大,所以镶嵌上去之后,左下对齐和左上对齐就没有任何差别。

如果是不等大的坐标排列,可以自己计算一下高度差,或加或减一下就好了。

unity ugui缩放+移动的更多相关文章

  1. Unity UGUI

    超详细的基础教程传送门:(持续更新中) Unity UGUI之Canvas&EventSystem:http://blog.csdn.net/qq992817263/article/detai ...

  2. Unity ugui屏幕适配与世界坐标到ugui屏幕坐标的转换

    我们知道,如今的移动端设备分辨率五花八门,而开发过程中往往只取一种分辨率作为设计参考,例如采用1920*1080分辨率作为参考分辨率. 选定了一种参考分辨率后,美术设计人员就会固定以这样的分辨率来设计 ...

  3. Unity UGUI —— 无限循环List

    还记得大学毕业刚工作的时候是做flash的开发,那时候看到别人写的各种各样的UI组件就非常佩服,后来自己也慢慢尝试着写,发现其实也就那么回事.UI的开发其实技术的成分相对来说不算多,但是一个好的UI是 ...

  4. Unity UGUI图文混排源码(三) -- 动态表情

    这里是根据图文混排源码(二)进一步修改的,其他链接也不贴了,就贴一个链接就好了,第一次看这文章的同学可以先去看看其他几篇文章 Unity UGUI图文混排源码(二):http://blog.csdn. ...

  5. Unity UGUI图文混排源码(二)

    Unity UGUI图文混排源码(一):http://blog.csdn.net/qq992817263/article/details/51112304 Unity UGUI图文混排源码(二):ht ...

  6. Unity UGUI图文混排源码(一)

    Unity UGUI图文混排源码(一):http://blog.csdn.net/qq992817263/article/details/51112304 Unity UGUI图文混排源码(二):ht ...

  7. Unity UGUI实现图文混排

    目前在unity实现图文混排的好像都是通过自定义字体然后在文本获取字符的位置,用图片替换掉图片标签,这样对于支持英文来说,并没有什么影响.然后对于中文来说就是一个相当麻烦的事了,毕竟图文混排多用于游戏 ...

  8. Unity UGUI Layout自动排版组件用法介绍

    Unity UGUI布局组件 本文提供全流程,中文翻译. Chinar 坚持将简单的生活方式,带给世人!(拥有更好的阅读体验 -- 高分辨率用户请根据需求调整网页缩放比例) Chinar -- 心分享 ...

  9. Curved UI - VR Ready Solution To Bend Warp Your Canvas 1.7,1.8,2.2,2.3 四种版本压缩包(Unity UGUI曲面插件),可以兼容VRTK

    Curved UI - VR Ready Solution To Bend Warp Your Canvas 1.7,1.8,2.2,2.3 四种版本压缩包(Unity UGUI曲面插件) 可以兼容V ...

随机推荐

  1. onethink框架显示Access denied for user 'root'@'localhost' (using password: NO)

    本地开发的时候使用的用户名是root,密码为空,它会生成两份.一份在Common/config.php里面,还有一份在Application\User\Conf/config.php 在linux环境 ...

  2. 阅读 用P4对数据平面进行编程

    引言 关于题目,对数据平面进行编程,在之前读过the road to SDN,软件定义网络的思想在于数控分离,其对网络行为的编程暂时只局限于网络控制平面.其转发平面在很大程度上受制于功能固定的包处理硬 ...

  3. node必学的Hello World实现--服务器实现

    node是JavaScript运行在后端的一种实现.而后端语言,不管是php,java都需要一个服务器才能跑起来,node如是. node的服务器较php而言,少了单独安装服务器的步骤,node的服务 ...

  4. 原生js实现自定义alert风格和实现

    2018年6月29 最新更新 添加函数节流,解决多次点击问题,添加单例模式,提高代码性能. <!DOCTYPE html> <html lang="en"> ...

  5. Jenkins系列-Jenkins添加git密钥对

    添加密钥 1.添加git用户和git密码对 ,用于git客户端从gitlab上拉取代码到本地

  6. Windows Server 2012四大版本介绍

    今天刚好要尝试安装Windows Server 2012,在网上百度了下发现有4个版本,分别是: Datacenter数据中心版. Standard标准版. Essentials版. Foundati ...

  7. css样式 一定要reset?

    有大神讲过了,直接看http://www.zhangxinxu.com/wordpress/?p=758

  8. 【题解】51nod 1806 wangyurzee的树

    看这道题目懵逼了好久, \(m <= 17\) 一眼容斥,然而并没有想到怎么求出生成树的个数.然后灵光一闪——我不是学过一个叫Prüfer编码的东西嘛?!那就完美解决啦~ Prüfer编码就是将 ...

  9. POJ2195:Going Home——题解

    http://poj.org/problem?id=2195 题目大意: 有些人和房子,一个人只能进一个房子,人走到房子的路程即为代价. 求所有人走到房子后的最小代价. ——————————————— ...

  10. 从零开始学Linux系统(三)安装CentOS-7及软件包管理操作

    推荐博文: VirtualBox安装CentOS7步骤详解: https://my.oschina.net/AaronDMC/blog/840753 如何安装CentOS7字符界面 :http://b ...