XAML学习笔记——Layout(三)
本篇随笔将介绍两种常见的布局——StackPanel和RelativePanel
StackPanel
StackPanel是一种应用很广的布局方式,无论在WPF还是在UWP当中,其中的子元素按照“栈”的结构排成一列(简单理解就是一个挨着一个的站成一排),其中子元素的排列方向根据Orientation值不同,可以分为水平方向(Horizontal)排列和竖直方向(Vertical)排列,默认是按照竖直方向排列。其中竖直方向排列比较典型的例子就是作为各种形式的列表(list)、组合框(ComboBox)、列表框(ListBox)还有一些菜单(
Menu
)中元素的布局方式,举个简单的例子(UWP版):
1 <StackPanel Margin="50" 2 Padding="10" 3 HorizontalAlignment="Center" 4 BorderBrush="BlueViolet" 5 BorderThickness="3" 6 CornerRadius="10"> 7 <TextBlock Margin="10" FontSize="20">How do you like your coffee?</TextBlock> 8 <Button Margin="10" HorizontalAlignment="Stretch">Black</Button> 9 <Button Margin="10" HorizontalAlignment="Stretch">With milk</Button> 10 <Button Margin="10" HorizontalAlignment="Stretch">Latte machiato</Button> 11 <Button Margin="10" HorizontalAlignment="Stretch">Chappuchino</Button> 12 </StackPanel>
效果如下:
Tip :
从UWP开始,StackPanel定义了新的border属性,可以直接用相关属性为StackPanel添加边框。这些属性主要包括:
- StackPanel.BorderBrush:边框颜色
- StackPanel.BorderThickness:边框粗细
- StackPanel.CornerRadius:边框圆角弧度
- StackPanel.Padding:边框内边距
上面的例子就用上述属性为StackPanel添加了一个“华丽”的外边框。上述例子展示了元素的竖直排列方式,我们也可以让布局元素按照水平方向排列在StackPanel中,水平方向排列比较常见的例子有窗口的“确认”、“取消”按钮,表单下面的“提交”、“取消”按钮等。再举个水平方向的简单例子:
1 <StackPanel Margin="8" 2 HorizontalAlignment="Center" 3 Orientation="Horizontal"> 4 <Button MinWidth="93">发布随笔</Button> 5 <Button MinWidth="93" Margin="10,0,0,0">保存随笔</Button> 6 <Button MinWidth="93" Margin="10,0,0,0">退出</Button> 7 </StackPanel>
所有的功能button按照水平居中方式排成一行:
StackPanel中子元素的排列方式从语义方面体现出子元素间的并列关系,所以开发中如果遇到若干并列关系元素的布局,可以考虑用StackPanel。如果想要调整布局元素在StackPanel中的位置时可以使用
Margin属性。同时,使用StackPanel时还需要特别注意一点:
- 当子元素按照竖直方向排列时,子元素的VerticalAlignment值固定为Stretch。
- 当元素按照水平方向排列的时候,子元素的HorizontalAlignment值同样固定为Stretch。
在这两种情况下,想要调整元素在布局容器中的位置只能通过调节Margin属性。这种“特性”决定了StackPanel中一般不会嵌套其他布局方式(否则会出现某些怪异现象)。
StackPanel从理论方面和实践方面都很好理解,暂且介绍到这里。。
RelativePanel
在以上介绍的三种布局中,子元素都是有一定规律性的排列在布局容器中,而RelativePanel则改变这种预定格式的布局方式,其中的子元素可在布局元素中随意排列,功能强大,用法灵活,而且RelativePanel是“响应式布局”实现的关键布局之一。想要理解RelativePanel就要理解其中“相对(Relative)“一词的含义,之所以称之为”相对“,就意味着子元素的位置一定与“相对目标”有关,按照“相对目标”的不同可以将RelativePanel中的布局属性分为以下两大类:
相对“布局容器”位置关系属性
在默认的情况下,RelativePanel布局容器中的子元素会在布局容器的(0,0)坐标点即左上角排列,我们可以通过为布局元素添加RelativePanel.AlignxxxWithPanel系列属性,来指明了子元素相对于布局容器的位置(上、下、左、右),主要包括:
属性 |
描述 |
当值为“True”时,元素位于布局容器底部并与底边对齐 |
|
当值为“True”时,元素位于布局容器顶部并与上边对齐 |
|
当值为“True”时,元素位于布局容器左侧并与左边界对齐 |
|
当值为“True”时,元素位于布局容器顶部并与右边界对齐 |
例:
1 <RelativePanel BorderBrush="BlueViolet" BorderThickness="2" Margin="10"> 2 <RelativePanel.Resources> 3 <Style TargetType="Button"> 4 <Setter Property="FontSize" 5 Value="25"/> 6 </Style> 7 </RelativePanel.Resources> 8 9 <Button Content="TopLeft" Background="CadetBlue" 10 RelativePanel.AlignTopWithPanel="True" 11 RelativePanel.AlignLeftWithPanel="True" 12 MinHeight="100" MinWidth="100"/> 13 <Button Content="BottomLeft" Background="DeepSkyBlue" 14 RelativePanel.AlignBottomWithPanel="True" 15 RelativePanel.AlignLeftWithPanel="True" 16 MinHeight="100" MinWidth="100"/> 17 <Button Content="TopRight" Background="RoyalBlue" 18 RelativePanel.AlignRightWithPanel="True" 19 RelativePanel.AlignTopWithPanel="True" 20 MinHeight="100" MinWidth="100"/> 21 <Button Content="BottomRight" Background="LightBlue" 22 RelativePanel.AlignBottomWithPanel="True" 23 RelativePanel.AlignRightWithPanel="True" 24 MinHeight="100" MinWidth="100"/> 25 </RelativePanel>
效果:
通过对四个button相对于布局容器位置属性的赋值,将它们放到了布局容器的四角。通过这类属性赋值的元素会严格按照边界对齐,如果要想实现居中效果就要借助于“相对布局面板居中”属性:
属性 |
描述 |
水平居中对齐于布局容器 |
|
竖直居中对齐于布局容器 |
将以上的居中属性和上面的例子结合,可以使布局元素的位置更加多样:
1 <RelativePanel BorderBrush="BlueViolet" BorderThickness="2" Margin="10"> 2 <RelativePanel.Resources> 3 <Style TargetType="Button"> 4 <Setter Property="FontSize" 5 Value="25"/> 6 </Style> 7 </RelativePanel.Resources> 8 9 <Button Content="Top" Background="CadetBlue" 10 RelativePanel.AlignTopWithPanel="True" 11 RelativePanel.AlignHorizontalCenterWithPanel="True" 12 MinHeight="100" MinWidth="100"/> 13 <Button Content="Bottom" Background="DeepSkyBlue" 14 RelativePanel.AlignHorizontalCenterWithPanel="True" 15 RelativePanel.AlignBottomWithPanel="True" 16 MinHeight="100" MinWidth="100"/> 17 <Button Content="Right" Background="RoyalBlue" 18 RelativePanel.AlignVerticalCenterWithPanel="True" 19 RelativePanel.AlignRightWithPanel="True" 20 MinHeight="100" MinWidth="100"/> 21 <Button Content="Left" Background="LightBlue" 22 RelativePanel.AlignVerticalCenterWithPanel="True" 23 RelativePanel.AlignLeftWithPanel="True" 24 MinHeight="100" MinWidth="100"/> 25 <Button Content="Center" Background="Blue" 26 RelativePanel.AlignVerticalCenterWithPanel="True" 27 RelativePanel.AlignHorizontalCenterWithPanel="True" 28 MinHeight="100" MinWidth="100"/> 29 </RelativePanel>
效果:
相较于以前只能通过HorizontalAlignment、VerticalAlignment和Margin调节元素在布局容器中相对位置的方式,RelativePanel的这种方式显得灵活许多。实际上,在RelativePanel中还包括另一系列改变元素在布局容器中位置的属性:相对“目标元素”位置关系属性。
相对“目标元素”位置关系属性
第一次接触这一系列属性的最先想到的是我WP上的动态磁贴,于是乎自己动手模拟了一个例子:
用这个呆萌的例子能很容易解释这一系列属性。拿FaceBook按钮为例,如果选择目标元素为WeiXin,那我们可以说它位于WeiXin下方并且和WeiXin左对齐;如果选择目标元素为Sina,则它位于Sina上方并且与Sina右对齐;若目标元素为QQ,则它位于QQ下方并与其右对齐。由此可见,相对“目标元素”位置关系属性可分为两大类:对齐关系和相对位置关系。
对齐关系
我们可以通过为布局元素添加RelativePanel.AlignxxxxWith系列属性,来指明子元素与目标元素的对齐方式,属性的值即为目标元素的x:Name值。这一系列属性主要包括:
属性 | 描述 |
AlignBottomWith | 对齐于目标元素的下边界 |
AlignTopWith | 对齐于目标元素的上边界 |
AlignLeftWith | 左对齐于目标元素 |
AlignRightWith | 右对齐于目标元素 |
相对位置关系
通过为布局元素指定RelativePanel.xxx系列属性,可以说明布局元素与目标元素的相对位置关系,这一系列属性主要包括:
属性 | 描述 |
Above | 在目标元素的上方 |
Below | 在目标元素的下方 |
LeftOf | 在目标元素的左边 |
RightOf | 在目标元素的右边 |
由上面介绍的一大系列属性和例子可以看出RelativePanel布局方式多样化,同一种布局往往可以通过很多中方式实现,正因如此,在使用过程中有可能遇到如下问题:
循环依赖
举一个简单的例子,在布局过程中如果指定:“A元素在B元素的上方,B元素在A元素的下方”,这种布局链中所有的元素位置都不固定的情况,就形成了循环依赖,此时在XAML设计器中会得到编译时异常:"RelativePanel error: Circular dependency detected. Layout could not complete." 这就要求我们在布局过程中选择目标元素时保证其位置固定,进而避免产生元素间的循环依赖。
关系冲突
从上面介绍的一“大系列”属性和例子中可以看出,RelativePanel布局十分灵活,但同样有可能引起关系冲突,比如指定A元素在B元素左边同时又和B元素右对齐,这样两条布局规则不能同时成立的话,就要通过指定优先级来决定到底一哪一条规则为准。这种优先级顺序即为本篇随笔介绍先关属性的顺序:
- 相对“布局容器”位置关系属性(AlignTopWithPanel, AlignLeftWithPanel, …) 优先级最高。
- 相对“目标元素”对齐关系属性(AlignTopWith, AlignLeftWith, …) 次之。
- 相对“目标元素”位置关系属性(Above, Below, RightOf, LeftOf) 优先级低。
Tip:
一般来讲,“相对布局面板居中”属性(AlignVerticalCenterWith, AlignHorizontalCenterWithPanel) 应用相对独立,并不会与其他属性发生冲突。
在学习RelativePanel的过程中,我一直有一个疑问,传统的位置关系属性 HorizontalAlignment 和 VerticalAlignment 会起什么作用?查询官方资料得知这两个属性的优先级最低,即有其他关系属性存在的情况下就会忽略这两个属性。但是我试了一下,就算没有其他位置属性存在,RelativePanel也一样会无视他俩。总之,这部分还是有待学习(在RelativePanel 中还是先用好相对应的布局属性吧。。)。。
这片随笔断断续续写了好长时间,感觉不太连贯。。
果然一篇随笔介绍两种布局篇幅有点大。。下篇准备只介绍一个——SplitView布局。