Avalonia系列文章之布局简介

news/2025/2/10 22:20:28/文章来源:https://www.cnblogs.com/hsiang/p/18703490

在UI设计中,页面布局非常重要,良好的布局不仅可以有效的利用空间,还能提升交互体验,以达到事半功倍的效果。所以对于Avalonia UI初学者来说,布局控件的了解与学习也非常的重要,今天以一些小例子,简述Avalonia UI框架中布局控件的使用,仅供学习分享使用,如有不足之处,还请指正。

布局系统

布局系统描述了容器对元素集合的成员进行测量和排列的过程。布局是一个密集的过程,Children集合越大,进行的计算越多。每次对子控件更改位置,都可能触发布局系统的新计算,所以不必要的调用可能会导致应用程序的性能下降。布局系统对子元素集合的每个成员完成两个传递:测量传递和排列传递。每个Panel提供自己的MeasureOverride和ArrangeOverride方法,以实现其特定的布局行为。常用的布局面板有以下几种:

  1. Panel    将所有子元素布局以填充 Panel 的边界
  2. Canvas    定义一个区域,您可以在其中使用相对于 Canvas 区域的坐标明确定位子元素
  3. DockPanel    定义一个区域,其中您可以相对于彼此将子元素水平或垂直地排列
  4. Grid    定义由列和行组成的灵活网格区域
  5. RelativePanel    将子元素相对于其他元素或面板本身排列
  6. StackPanel    将子元素排列成一行,可以是水平或垂直方向
  7. WrapPanel    将子元素按从左到右的顺序放置,当内容到达容器框的边缘时,将在下一行中断。后续排序顺序是顺序从上到下或从右到左,这取决于 Orientation 属性的值。

注意:在 WPF 中,Panel 是一个抽象类,通常使用没有行/列的 Grid 来布局多个控件以填充可用空间。在 Avalonia 中,Panel 是一个可用的控件,其布局行为与没有行/列的 Grid 相同,但运行时占用更少的资源。

对齐与边距

在Avalonia UI中,提供了四个常用属性(HorizontalAlignment、Margin、Padding和VerticalAlignment),用于精确定位子元素。它们是控制元素在应用程序中位置的基础。主要如下:

  • HorizontalAlignment属性声明了要应用于子元素的水平对齐特性,常用的属性值有四个:
    • Left    子元素与父元素分配的布局空间的左侧对齐。
    • Center    子元素与父元素分配的布局空间的中心对齐。
    • Right    子元素与父元素分配的布局空间的右侧对齐。
    • Stretch (默认)    子元素被拉伸以填充父元素分配的布局空间。明确的Width和Height值优先级更高。
  • VerticalAlignment属性声明了要应用于子元素的垂直对齐特性,常用的属性值有四个:
    • Top    子元素与父元素分配的布局空间的顶部对齐。
    • Center    子元素与父元素分配的布局空间的中心对齐。
    • Bottom    子元素与父元素分配的布局空间的底部对齐。
    • Stretch(默认)    子元素被拉伸以填充父元素分配的布局空间。明确的Width和Height值优先级更高。
  • Margin属性描述了元素与其子元素或同级元素之间的距离。Margin值可以是相同的,通过使用像Margin="20"的语法,元素将使用相同的20个设备独立像素的Margin。Margin值也可以是四个不同的值,每个值描述了应用于左、上、右和下的不同边距(按顺序),如Margin="0,10,5,25"。在许多情况下,统一的边距是不合适的。在这些情况下,可以应用非统一间距。正确使用Margin属性可以非常精确地控制元素的渲染位置及其相邻元素和子元素的渲染位置。
  • Padding属性描述了元素与其内容之间的距离,在大多数方面与Margin相似。Padding属性仅暴露在少数类上,主要是为了方便。Border、TemplatedControl、和TextBlock是暴露了Padding属性的类的范例。Padding属性通过指定的Thickness值扩大了子元素的有效尺寸。

注意:HorizontalAlignment和VerticalAlignment属性描述了一个子元素应该如何在父元素分配的布局空间内定位。元素上明确设置的Height和Width属性的优先级高于Stretch属性。如果明确设置了Height和Width,再将HorizontalAlignment设置为Stretch,这样会忽略Stretch属性。

对齐与边距应用示例如下所示:

<Window xmlns="https://github.com/avaloniaui"xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"x:Class="AvaloniaApplication2.MainWindow"Title="AvaloniaApplication2"><Border Background="LightBlue"BorderBrush="Black"BorderThickness="2"Padding="15"><StackPanel Background="White"HorizontalAlignment="Center"VerticalAlignment="Top"><TextBlock Margin="5,0"FontSize="18"HorizontalAlignment="Center">Alignment, Margin and Padding Sample</TextBlock><Button HorizontalAlignment="Left" Margin="20">Button 1</Button><Button HorizontalAlignment="Right" Margin="10">Button 2</Button><Button HorizontalAlignment="Stretch">Button 3</Button></StackPanel></Border>
</Window>

示例效果如下图所示:

Panel控件

Panel是Avalonia提供的布局支持的元素的基类,默认情况下,Panel和没有行列个Grid相同,可以采用对齐或边距(HorizontalAlignment、Margin、Padding和VerticalAlignment)进行定位,但相对于Grid等复杂布局容器,Panel运行时占用的资源较少。示例如下所示:

<Panel><TextBlock Background="LightGray" Text="Left" Width="100" Height="20" HorizontalAlignment="Left" /><TextBlock Background="LightGray" Text="Right" Width="100" Height="20" HorizontalAlignment="Right"/><TextBlock Background="LightGray" Text="Top" Width="100" Height="20" VerticalAlignment="Top" /><TextBlock Background="LightGray" Text="Bottom" Width="100" Height="20" VerticalAlignment="Bottom"/>
</Panel>

示例效果如下所示:

如果将Panel中的元素换成Button,将会有不同的效果,示例代码如下:

<Panel><Button Background="LightGray" Content="Left" Width="100" Height="30" HorizontalAlignment="Left" /><Button Background="LightGray" Content="Right" Width="100" Height="30" HorizontalAlignment="Right"/><Button Background="LightGray" Content="Top" Width="100" Height="30" VerticalAlignment="Top" /><Button Background="LightGray" Content="Bottom" Width="100" Height="30" VerticalAlignment="Bottom"/>
</Panel>

示例效果如下所示:

思考一下:都是Panel布局,将TextBlock换成Button,为什么效果会不同呢?

Canvas

Canvas(画布容器)允许按绝对坐标(x,y)定位子元素。子元素可以绘制在不同的位置,也可以绘制在同一个位置,如果两个控件在Canvas容器中的位置相同,则依据出现的顺序进行显示。Canvas提供了最灵活的布局支持,Height和Width属性定义画布的大小,其中的元素被赋予相对于Canvas区域的绝对坐标。通过四个附加属性 (Canvas.Left、Canvas.Top、Canvas.Right 和 Canvas.Bottom )来精确地控制对象在 Canvas 内的位置,从而使开发人员可以精确定位和排列元素在屏幕上的位置。

Canvas布局示例代码,如下所示:

<Canvas><Button Background="Red" Content="Red" Width="100" Height="100"  /><Button Background="Green" Content="Green" Width="100" Height="100" Canvas.Left="100" Canvas.Top="100"/><Button Background="Blue" Content="Blue" Width="100" Height="100" Canvas.Left="200" Canvas.Top="200" /><Button Background="Yellow" Content="Yellow" Width="100" Height="100" Canvas.Right="100" Canvas.Bottom="100"/>
</Canvas>

示例效果如下所示:

在Canvas中,如果没有明确设置子元素在容器中的位置,则默认位于左上角,即Left,Top为0。另外,Canvas的默认行为是允许子元素绘制在父Canvas界限之外,如果不希望出现这种情况,可以设置ClipToBounds属性为True,会自动裁剪界限之外的内容。

在上述示例中,Canvas.Left,Canvas.Top,Canvas.Bottom,Canvas.Right,作为Canvas的附加属性,应用在Canvas容器中的子元素上,则前缀“Canvas.”不可以省略。如果省略,且子元素本身也有Left,Top等属性,则会造成编译器无法准确识别。

DockPanel

DockPanel(停靠面板)使用附加属性DockPanel.Dock来设置子内容元素在容器边缘的位置。当 DockPanel.Dock 设置为 Top 或 Bottom 时,它会将子元素放置在彼此的上方或下方。当 DockPanel.Dock 设置为 Left 或 Right 时,它会将子元素放置在彼此的左侧或右侧。LastChildFill 属性决定了最后一个作为 DockPanel 子元素添加的元素的位置。

如果没有指定DockPanel的Width和Height属性,它的大小根据内容来确定。大小可以根据其子元素的大小进行增长或减小。然而,当指定了这些属性并且没有足够的空间来容纳下一个指定的子元素时,DockPanel 不会显示该子元素或随后的子元素,并且不会对随后的子元素进行测量。

DockPanel示例源码,如下所示:

<DockPanel LastChildFill="True"><Border Height="25" Background="SkyBlue" BorderBrush="Black" BorderThickness="1" DockPanel.Dock="Top"><TextBlock Foreground="Black">Dock = "Top"</TextBlock></Border><Border Height="25" Background="SkyBlue" BorderBrush="Black" BorderThickness="1" DockPanel.Dock="Top"><TextBlock Foreground="Black">Dock = "Top"</TextBlock></Border><Border Height="25" Background="LemonChiffon" BorderBrush="Black" BorderThickness="1" DockPanel.Dock="Bottom"><TextBlock Foreground="Black">Dock = "Bottom"</TextBlock></Border><Border Width="200" Background="PaleGreen" BorderBrush="Black" BorderThickness="1" DockPanel.Dock="Left"><TextBlock Foreground="Black">Dock = "Left"</TextBlock></Border><Border Background="White" BorderBrush="Black" BorderThickness="1"><TextBlock Foreground="Black">This content will "Fill" the remaining space</TextBlock></Border>
</DockPanel>

示例效果如下所示:

注意,默认情况下,DockPanel 元素的最后一个子元素将“填充”剩余的未分配空间。如果不希望出现这种情况,可以将 LastChildFill 属性设置为 false。

Grid

Grid容器结合了绝对定位和表格数据控件的功能。Grid允许定义灵活的行和列分组,并且可以在多个Grid之间共享大小信息。在Grid控件中,通过ColumnDefinitions="Auto,*,*,*,*" RowDefinitions="Auto,Auto,*,Auto"实现定义行列,多行多列用逗号隔开,子元素通过Grid.Row,Grid.Column附加属性进行定位。在XAML中,行列的大小可以通过几种方式进行设置:

  1. 通过Star(*)进行设置,如Width="*"或Width="2*",则该行列会按比例获得剩余可用空间。
  2. 通过Auto进行设置,如Width="Auto",则行或列会根据内容的大小进行分配空间。
  3. 绝对大小,默认单位为像素值,如Width="100",表示宽度为100px。

如下Grid代码定义了4行5列,具体如下所示:

<Grid Background="Gainsboro" HorizontalAlignment="Left" VerticalAlignment="Top" Width="425" Height="165"ColumnDefinitions="Auto,*,*,*,*" RowDefinitions="Auto,Auto,*,Auto"><TextBlock Grid.Row="0" Grid.Column="1" Grid.ColumnSpan="4" Text="选择打开的文件." TextWrapping="Wrap" /><TextBlock Grid.Row="1" Grid.Column="0" Text="Open:" /><TextBox Grid.Row="1" Grid.Column="1" Grid.ColumnSpan="5" /><Button Grid.Row="3" Grid.Column="2" Content="OK" Margin="10,0,10,15" /><Button Grid.Row="3" Grid.Column="3" Content="Cancel" Margin="10,0,10,15" /><Button Grid.Row="3" Grid.Column="4" Content="Browse ..." Margin="10,0,10,15" />
</Grid>

示例效果如下所示:

StackPanel

StackPanel(栈面板)允许在指定的方向上堆叠元素,默认的堆叠方法是垂直的,如果想要水平方向排列,可以通过Orientation属性进行设置,来控制子元素内容的排列方向。

StackPanel示例代码如下所示:

<StackPanel HorizontalAlignment="Center" VerticalAlignment="Top" Spacing="25"><Button Content="Button 1" /><Button Content="Button 2" /><Button Content="Button 3" />
</StackPanel>

示例效果如下所示:

WrapPanel

WrapPanel用于按照从指定的顺序定位子元素,并在其父容器的边缘到达时将内容换行。WrapPanel和StackPanel一样,可以通过Orientation属性指定子元素排列的方向,默认为水平排列。

WrapPanel示例代码如下所示:

<Border HorizontalAlignment="Left" VerticalAlignment="Top" BorderBrush="Black" BorderThickness="2"><WrapPanel Background="LightBlue" Width="200" Height="100"><Button Width="200">Button 1</Button><Button>Button 2</Button><Button>Button 3</Button><Button>Button 4</Button></WrapPanel>
</Border>

示例效果如下所示:

UniformGrid

UniformGrid提供统一的网格布局面板,此网格布局面板中的所有单元格大小相同,与Grid不同,此网格布局面板不支持显示设置行,和列,也没有Grid.Row,Grid.Column等附加属性,它主要用于显示大小相同的子元素控件。UniformGrid常用属性如下:

  1. 行和列:UniformGrid 使用 Rows 和 Columns 属性来确定其子元素的布局。如果只设置其中一个属性,UniformGrid 将自动计算另一个属性,以创建适合子元素总数的网格。如果两个属性都不设置,UniformGrid 默认为 1 行 1 列的网格。
  2. FirstColumn:FirstColumn 属性允许您在网格的第一行中留下一定数量的空单元格。

UniformGrid示例如下所示:

<UniformGrid Rows="3" Columns="4"><Rectangle Width="50" Height="50" Fill="#330000"/><Rectangle Width="50" Height="50" Fill="#660000"/><Rectangle Width="50" Height="50" Fill="#990000"/><Rectangle Width="50" Height="50" Fill="#CC0000"/><Rectangle Width="50" Height="50" Fill="#FF0000"/><Rectangle Width="50" Height="50" Fill="#FF3300"/><Rectangle Width="50" Height="50" Fill="#FF6600"/><Rectangle Width="50" Height="50" Fill="#FF9900"/><Rectangle Width="50" Height="50" Fill="#FFCC00"/><Rectangle Width="50" Height="50" Fill="#FFFF00"/><Rectangle Width="50" Height="50" Fill="#FFFF33"/><Rectangle Width="50" Height="50" Fill="#FFFF66"/>
</UniformGrid>

在上面的示例中,每个 Rectangle 被自动分配到网格中的一个单元格,按照它们被添加的顺序进行分配。示例效果如下所示:

布局嵌套

在实际应用中,不同的Panel可以相互嵌套,以创建复杂的布局。虽然理论上可以无限嵌套面板元素,但嵌套越多,性能越低。所以熟练掌握各种布局容器的特点,才能根据业务需求,采用合理的布局面板,这样不仅能提升性能,还会起到事半功倍的效果。

以上就是《Avalonia系列文章之布局简介》的全部内容,希望可以抛砖引玉,一起学习,共同进步。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.hqwc.cn/news/881876.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

ACM寒假集训第四期

ACM寒假集训第四期 有理数取余 思路 bx=a mod m x=((a mod m) * ( b^(-1) ) mod m)) mod m; 问题就转化为如何求解 b 的逆元 b x = 1 mod m ,b对m的逆元,当 gcd(b,m)=1 时才存在。存在 bx+my=1 通过辗转相除法可以得到b,m的最大公约数然后根据最后得到的一系列等式合并为 bx+m…

昆明理工大学2025年硕士研究生调剂汇总表(2月10日更新)

这是今年昆明理工大学调剂信息,目前只更新了部分学院的部分专业,后续会持续更新。 【腾讯文档】昆明理工大学2025年硕士研究生调剂汇总表 https://docs.qq.com/sheet/DZERIbnpPb3JjeHFO

推荐一款人人可用的开源 BI 工具,更符合国人使用习惯的数据可视化分析工具,数据大屏开发神器!

前言 今天大姚给大家推荐一款人人可用的开源、免费的 BI 工具,更符合国人使用习惯的数据可视化分析工具,数据大屏开发神器,Tableau、帆软的开源替代:DataEase。工具介绍 DataEase是一个开源的数据可视化分析工具,可以帮助用户快速分析数据并洞察业务趋势,从而实现业务的改…

清华大学推出的 DeepSeek 从入门到精通(104页)免费教程!

前言 最近 DeepSeek 的出现让 AI 在国内掀起了一股浪潮,各大媒体、平台都在讨论和推广 DeepSeek,帮助各行各样使用 AI 不再有困难。今天大姚给大家分享一个由清华大学推出的、免费的:DeepSeek从入门到精通实用教程,该教材有着足足的104页能够快速的帮助大家了解和使用DeepS…

卞俊良

卞俊良 你猜 你猜我猜不猜

P1314 [NOIP 2011 提高组] 聪明的质监员(前缀和)

这道题最核心就是二分W,然后对于每一个W都构建一个前缀和数组,但要注意ans不能开太小,我开INT_MAX都不行,其次就是二分左右端点的变化,如果s-y>0说明满足要求的点多了,这时候我们要提高标准,就是让W增大,及让beign=W+1,反之让end=W-1;如果s=y,此时ans=0;这时候我…

读读源码-ArrayList究竟是怎么实现增强for循环的?

以我的认知来说,java中的ArrayList实现List,List又是继承Collection,往后就不太清楚了。 今天看源码的时候发现Collection继承了Iterable,Iterable接口的作用是允许对象称为for-each loop语句的目标。 因此如果想了解ArrayList如何实现循环,我们必须先从Iterable看起 1.集…

“此电脑”不是“我的电脑”怎么办

在以前,我们可以按住win+E就可以打开到有盘符的界面(直接看见C盘,D盘,E盘……),现在win11没有这个效果了,我还得再在左边的选项里寻找“此电脑”再进入我想要的“我的电脑”界面,真麻烦!无缘无故多了几个点击步骤,效率真低! 今天,我想改变这个效果!自已自足!。。…

香港海底光缆-转载2020

转自:http://live.xiaohongshu.com.sdwan.ltd/index.php?m=home&c=View&a=index&aid=132香港作为全球重要数据传输驿站之一,其网络传输能力自然不可小瞧。根据香港政府通讯事务管理局办公室给出的资料,截至2019年1月,香港有十一个海缆系统,即亚非欧1号光缆系…

miniconda安装和配置

第一步,下载和安装访问Download Anaconda Distribution | Anaconda,跳过注册"Skip registration",进入下载界面往下拉,选择miniconda的下载。安装时候注意勾选PATH路径的配置选项。第二步,安装完成后通过Anaconda Prompt打开命令行,看到提示符前面有(base)字…