首先,widget的首次对齐执行是在首次update前start后,而这之间并没有事件回调函数,也就是说无法插手这里的事。
那么,问题来了,如果我想在start、onLoad、onEnable里面设置某个物体的坐标、缩放、锚点,而这个时候其父物体或者说上层节点受到了widget控制,那就悲催了,就会发现错位了,有可能是锚点错误,有可能是位置错位,反正就是乱套了。
而widget默认是勾选只执行一次的,但是这一次却是不受控制或者说无法控制,除非手动调用对齐。
我认为最合理的首次对位时机应该是位于onLoad或者onEnable里。
我已经被这个时机的问题恶心了好多次了,甚至我相信也有人除了问题却并不知道问题引发的核心原因是执行时机不合理,不知道官方会不会进行调整。
首次对齐不是在 update 前 start 后,而是在当帧的渲染前。
这样的目的是让用户在代码里对坐标,对 widget 参数的调整能够生效。
如果改成 onLoad/onEnable,那用户对场景的修改,将无法应用到 widget 中。
我也觉得不合理,我用widget做的适配,在onload里根据这个写的代码就不对。
确实有这个问题,我目前的解决办法是,重写一下Widget,重新写的widget继承于cc.widget,在重写的widget组件的onload函数里调用一下updateAlignment函数,然后再移除掉这个widget组件,这样暂时勉强解决了这个问题。。。
updateAlignment?
任何时候都不应该假设 widget 已经对齐成功。要使用 widget 对齐好的结果,都先调用一次 widget.updateAlignment。这才是正确方式。
这个问题比较悲催的是在onLoad里面去取坐标存起来,如果目标结点是在几层的根结点,要一层一层的去先取widget先updateAlignment.为了简单,我们都是setTimeout(function{},0.1)去取坐标,代码看起来就比较奇怪。
楼主说得这个很有意义,但要cocos改的可能性不大,个人觉得比较合理的处理方式是在onLoad前所有widget生效一次,在渲染前如果调整了参数再生效一次,就是类似脏矩阵的做法。
脏检测确实是最终方案。不过你说的要一层一层去 updateAlignment 好像是没必要的,因为 updateAlignment 本来就会自动调用父节点的 updateAlignment。
原来不只是我一个人会这么做ui,我也是,但是在onload、onenable和start里一层一层手动updateAlignment也没用,因为……这时候渲染根本就还没有开始,而第一次对齐是在渲染前和第一次update和lateUpdate后(在这之前手动调用对齐也没用,因为这个时候画面尺寸还没有初始化,不能获得,也就是说对齐不了),这个地方完全没法控制。以前长期使用unity的ugui,从来没有因为顺序而出现问题,因为人家的对齐时机是在onLoad前的。
特别是在关卡加载的时候的onLoad里,因为没有开始渲染,画面尺寸没有,不管你做什么updateAlignment都没用,除非你延时处理,但是延时处理就会闪啊不是么……如果这个对齐策略是在onLoad前的,那要是你像自己修改了参数再对齐,那手动就可以啊。
只不过啊,基于cocos底层基因的原因,是根本没法放到onLoad前吧,因为新加载关卡的时候onLoad发生在渲染画面大小初始化之前,我觉得官方用before visit事件来处理应该是为了避开这个问题。
用cocos的api去取一个坐标,发现这个坐标很可能不是你想像的那样的,这种感觉真的不好。是否在要文档里加上说明:在取坐标前先要updateAlignment,而且updateAlignment后的坐标也不一定是你想像的那样的。
为什么这样写代码,因为有时候调用了move action,需要回到原位置,就需要一个地方去存这个初始化位置,很尴尬,发现这个坑后写代码都不自然了,总觉得这个坐标会出错,写多了,特别是新手跑过来看你的代码,觉得你的代码怎么写得这么奇怪,好烂,到处setTimeout不是知道是什么鬼,有时setTimeout也会出问题。
文档是有这么写。不过坐标不一定是你想像那样,这个就不是 widget 的问题了。因为在你获取时,渲染还没初始化,所以不管怎样肯定对齐不了。
谢谢反馈,不过如果有这种和逻辑强关联的需求,还是建议自己实现一套 UI 对齐方案,而不是采用现有方案。目前的 Widget 实现比较简单,主要是为了做静态 UI 适配的。如果要加上脏检测,对性能和对引擎的架构都会不太友好。之后我们有足够人手的时候再重新考虑下这个需求吧。
其实吧……自己实现也只能应对动态生成的东西,因为很多时候,我更喜欢在编辑器搭建完全显示的ui,然后游戏运行前初始化隐藏或者挪到其它地方,做好动画前的准备,然后运行的时候播放ui动画(什么淡入淡出啊、滑进啊之类的)。如果ui是动态生成的,那这个无关紧要了,因为关卡加载的以后再动态生成的话,随便在onLoad对齐一下就好了,但是如果关卡是刚加载我就对齐那就麻烦了,因为渲染还没有初始化,无法获得画面大小,但是onLoad和start却已经执行了,so,这个时候就只能延迟对齐了,所以只能闪一下,或者先把东西隐藏起来,然后延时显示并初始化位置,我想,不管是新手还是老手,看到这样“古怪”的逻辑代码都会很不爽的。
解决这个问题的根本就在于让onLoad发生在渲染初始化之后,不过嘛,这种牵涉到底层的关系改动还真不小,我估计官方是不会改的了,cocos的基因确实差了点。
这个方向是错误的,逻辑怎么可能在渲染之后
你的结论是对的,可能 cocos 基因确实不怎样,但是在这个问题上,这两者没有因果关系。widget 这是我单方面的决策,如果是 cocos 的基因,肯定会一开始就把 widget 做成全自动更新的,而不是现在这样。
这个才是关键点好吧。这一块我们会再跟进的。你方便提交一个 demo 吗?就是你说会闪一下的 demo。
使用 widget 一定要把那个默认的 勾勾 去掉,否则没法用。
我也感觉布局很奇怪。要像QT或wxWidgets那样好用就好了。并且我觉得像素和百分比可以同时存在,因为这样可以应对更复杂的布局情况。
现在就是同时存在的,你一定没有试过填入一个%.