我们在开发中经常会使用Align组件来定位子组件的位置。通常会用到几个常用的相对位置,比如:alignment:Alignment.bottomRight,右下角。最近看了官方关于对齐的文档:Alignment(x,y)Align中的计算解释好像有点不对,结合相关源码,终于搞明白了。然后发现网上的教程解释大部分都是错误的。下面分享一下我对Align对齐原则的理解。前置知识:AlignmentAlignment的工作原理是先在一个矩形中建立一个虚拟坐标系。这个虚拟坐标系的原点就是矩形的中点,那么(x,y)就是这个虚拟坐标系中的锚点,并且规定(x,y)的值代表一个相对值,对于例如Alignment(0.0,0.0)为中点,Alignment(1.0,1.0)为右下角,如图:xin(x,y)相对值的单位是宽度的一半rectangle,例如2.0相当于矩形的整个宽度;y也一样,y的单位是矩形高度的一半。然后通过公式转化为以矩形左上角为原点的坐标系中的锚点。转换公式如下:(x*w/2+w/2,y*h/2+h/2),其中w为矩形的宽度,h为矩形的高度。结合下面的示意图来理解计算过程:绿色框为矩形,黑色坐标轴为虚拟坐标系,蓝色坐标轴为原点在矩形左上角的目标坐标系。以虚拟坐标轴上的横坐标x为例,转换后的目标点横坐标x'=矩形宽度的一半加上x*矩形宽度的一半(虚拟坐标轴上x的单位是宽度的一半矩形)。比如Alignment(2.0,0.0)的横坐标转换后的值为矩形宽度的1.5倍,而不是矩形宽度的两倍。Align是如何工作的在Align的官方文档中有一句话:Howitworksalignment属性描述了child坐标系中的一个点和这个widget坐标系中的一个不同的点。Align小部件定位子项,使两个点彼此对齐。意思是,首先利用alignment属性的描述,在子组件的坐标系中找到一个点,在Align组件的坐标系中找到另一个点;然后对齐将子组件放置在这两点重合的位置。错误解释从上面的描述可以看出,最终的放置坐标也和Align的大小有关,因为在这个过程中Align是用alignment来计算一个点的。但是我从官方文档的例子描述中只看到计算是和子组件相关的:而且我在网上看到的一些教程的解释也是错误的,比如这个:要证明这个错误很简单,把AligninaContainer,然后设置alignment为Alignment(1.0,0.0),然后随机放置一个子组件,例如:Container(height:120,width:200,color:Colors.green.withOpacity(0.6),child:Align(alignment:Alignment(1.0,0.0),child:Container(width:60,height:60,color:Colors.red,),),),你会发现无论怎么改变外层Container的宽度,右边内部红色矩形的边始终与外部Container的右侧重合。如果定位坐标仅相对于子组件的宽度,这将如何工作?以我的理解,官方文档中已经给出了计算原理,但是没有给出具体的公式。我查看了相关的源代码并确认其工作原理的描述是正确的。下面我将用一个简单的例子来说明计算过程并给出正确的计算公式。上图中绿色矩形是Align的大小,红色是子组件。我还是用Alignment(1.0,0.0)来说明。Alignment(1.0,0.0)描述的点的横坐标在绿色矩形和红色矩形的右边界。如果Align是根据这个位置来定位子组件,那么红色矩形应该在红色虚线框内。但根据其工作原理的描述,Align在放置子组件时,会出现两点重合,即红色矩形右边框的点与绿色矩形右边框的点重合。这时我们只需要从红色虚线框的位置移动到实线的位置即可,即:Align中锚点的横坐标减去子组件中锚点的横坐标:alignWidth/2+x*(alignWidth/2)-childWidth/2-x*(childWidth/2)坐标的y值也可以用类似的过程来描述,所以最终定位点的计算公式应该是:varx=(alignWidth-childWidth)/2+x*((alignWidth-childWidth)/2);vary=(alignHeight-childHeight)/2+x*((parentHeight-childHeight)/2);最后,如果对齐是FractionalOffset,也可以用类似的过程来描述定位。FractionalOffset和Alignment的区别在于,FractionalOffset在虚拟坐标系中的原点在矩形的左上角,而FractionalOffset(x,y)中x的单位是矩形的整个宽度,而不是一半。Align中的定位仍然遵循两个FractionalOffset点以保持重合。
