UI界面布局容器与布局策略概述

Wesley13
• 阅读 563

本文描述了UI界面的容器与布局策略。主要从理论角度论述原理和实现思路,并包含一些容器的样例贴图。

本文写于2016年2月,现发布于博客和大家分享。原文是工作需要做的研究,博客基于原始草稿,并做了一定删减和增补。

UI界面的基本组成单位是UI元素,容器是用于容纳多个子元素的组件。布局实际上是一种算法策略,用于计算子元素在容器中的位置排列。

布局管理器用于管理容器布局策略,有两种实现方式:

  • 每种布局策略实现特定容器
  • 容器可以指定不同的布局策略(例如Swing)

一种常用的设计是每种布局对应一个容器,好处就是入门门槛低,容易上手,但容易造成仅仅为了布局的容器堆叠。而让容器可以指定不同布局策略是一种灵活的实现方式,但是使用起来比较繁琐。对于一个成熟产品来说,同时提供可以自由指定布局策略的容器,同时提供常用的布局容器,是一种比较好的方案。

对于复杂界面来说,容器嵌套层次太多容易造成冗余的布局调用,随着嵌套层次的增加而减低布局效率。扁平化容器层级能够提高界面布局效率。如何减少容器组合的嵌套层级?可以考虑将一些常用的嵌套方案,封装为一个固定的组合布局容器。

布局策略 Layout Policy

布局策略可以抽象为5种基本类型:

  • Coordinate Based 基于坐标
  • Constraint Based 基于约束
  • Linear 线性
  • Layered 分层
  • Grid 网格

基于坐标的布局策略 Coordinate–Based

这是最基本的布局策略,子元素可以用Bounds(Location和Size)来决定在容器中的显示边界(Boundary)。

基于约束的布局策略 Constraint-Based

这是一种相对定位的布局策略,对子元素设置约束条件,当容器变化时,子元素的边界遵循约束发生变化。

  • Relative Positioning 相对定位 设置元素的left, top, right, bottom相对父容器的位置。例如Java的SpringLayout。

  • Anchor Points 锚点 一个界面元素具有9个锚点:上、下、左、右、中心、左上、右上、右下、左下。当设置了元素的Bound边界后,元素可以定位在容器中。此时,可以指定一个或多个锚点,则当容器边界变化时,元素的锚点保持相对位置不变,单个锚点可以让元素跟随容器平移,多个锚点可以让元素跟随容器的改变而平移+缩放。

  • Dock 停靠 元素可以停靠在容器的指定位置上,共有上下左右中五个位置。Dock和Anchor是WinFrom的基本布局策略。Dock布局是Anchor的一种简化。在Java里也称为BorderLayout,采用东南西北中来描述五个方位。

  • Guide Lines 参考线。 例如BaseLine、Constraint Row, Constraint Column。同时设置元素的边界相对参考线的位置

线性布局策略 Linear

所有元素沿着一个方向延展。可以派生出横向、纵向、以及可以折行的流式布局等。

这种布局策略简单有效,是界面布局中最常用的布局策略。通过组合可以实现大多数常用的界面布局。

以下容器属于线性布局策略:

  • HBox
  • VBox
  • FlowLayout
  • SpitContainer

在不同的实现中有一些扩展属性,例如flex属性可以指定某个元素自适应,还有指定对齐方式的属性等。

Flow Layout流式布局也是非常常用,在某个方向如果元素抵达边界则自动换行,从而可以多行展示。

分层布局策略 Layered

容器被切分成多个层,每层可以容纳一个或多个元素。有两种分支:

  • Stacking 叠放 每次显示一层,可以在层之间切换,每层的元素大小相同,一般为最大的元素大小。例如CardBox卡片盒容器。

  • Overlapping Overlays 覆盖 同时显示所有层,不同层的元素之间相互覆盖。注意这种覆盖布局,只有顶层元素可以交互,而非顶层元素虽然未被顶层元素遮盖的部分可见,但不响应事件。

以下容器属于此类布局策略类型:

  • CardBox
  • TabNavigator
  • Accordion

卡片盒的行为就像是不带标签页的TabNavigator,当然实现思路有一些差异。

而手风琴则更为特殊一些,老式Windows控制面板有类似例子,后来也是经久不衰,有很多演变。

网格布局策略 Grid

将容器按照行(Row)、列(Column)交叉分割为单元格(Cell),所有元素限制在单元格内,相对单元格对齐。

  • Grid 表格 表格按照Row和Column切分,每个格子大小可以不同,由行来决定高度,由列来决定宽度。元素可以占用一个或多个Cell单元格,通过单元格的RowSpan和ColSpan来定义。

  • Tile 平铺 所有的格子总是大小相同,元素可以占用一个或多个格子。如果元素大小小于单元格,则按照定义对齐(一般是左上角对齐)单元格。平铺策略的单元格大小一般是固定或是自适应的,按照可见视图的所有元素计算出单元格大小,所有单元格保持一致大小。单元格大小确定后,元素再按照对齐定义在单元格内对齐。

容器 Containers

通用容器列表

  • Box (HBox, VBox) 线性布局,横向、纵向
  • DockPanel 停靠布局,上下左右中
  • SplitContainer 分割容器
  • CardBox 卡片盒布局,单页显示
  • Accordion 手风琴布局,单项展开
  • Grid 表格布局
  • ToolBox, ToolBar 工具盒,工具条
  • Absolute 绝对定位
  • Relative 相对定位布局
  • TileLayout 格子布局
  • Scroller 滚动条
  • SideBar 侧边栏,可以折叠
  • Disclosure / Expander (Collapsible Panel) 扩展器,点击展开、收缩的扩展区域
  • Ribbon 带子(参见Office)
  • MenuButton 菜单按钮,点击展开浮动面板

HBox & VBox - Linear 线性布局

线性布局是最常用的布局容器,横向布局使用HBox,纵向布局使用VBox。原理并不复杂,只有几条简单的规则。一个盒子可以将元素布置在两个方向之一,水平或垂直。水平盒子将它的元素进行水平排列,而垂直盒子将它的元素进行垂直排列。

代码示例

<hbox>
  <!-- horizontal elements -->
</hbox>

<vbox>
  <!-- vertical elements -->
</vbox>

<box orient="vertical">

下面例子展示怎么垂直放置三个按钮。示例代码是XUL的布局格式。

UI界面布局容器与布局策略概述

<?xml version="1.0"?>
<?xml-stylesheet href="chrome://global/skin/" type="text/css"?>

<window id="vbox example" title="Example"
xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">

<vbox>
  <button id="yes" label="Yes"/>
  <button id="no" label="No"/>
  <button id="maybe" label="Maybe"/>
</vbox>

</window>

CSS新的FlexBox - 流式布局

CSS新标准中的FlexBox弹性容器是流式布局的一种完备实现。

UI界面布局容器与布局策略概述

UI界面布局容器与布局策略概述

分割容器 SplitContainer / DividedBox

一般使用一个独立的容器SplitContainer,作为一个预定义的带有分隔条的容器。其中包含两个子元素,并可以指定分隔条的方向。分隔条可以通过鼠标拖拽改变被分隔的两个区域的大小。

BoxSplitter分隔条可以放置在HBox或VBox中,自然显示为一个分隔条。 但要注意,由于线性布局可以放置多个串行元素,如果一个分隔条之后有多个元素,那么必须指定当Splitter调整位置时,哪个元素的大小将自动改变。

卡片盒 CardBox - 层叠容器

  • CardBox 每层称为Card
  • ViewStack 每层称为Frame,
  • PanelManager 每层称为Panel,

层叠容器的典型案例就是向导Wizard,点击下一步、上一步时,内容区域页面切换,同一时间只有一个页面显示。

用CardBox命名比较形象,就像一个名片盒,里面放置一张张名片,放在最上面的卡片可见。Stack原本的含义就是叠放,就像编程语言中的栈集合或栈内存,只能看到最外的一层,里面的所有层次都是在黑盒内不可见。

CardBox使用SelectedItem或SelectedIndex来访问或切换当前展示的卡片。

UI界面布局容器与布局策略概述

典型案例,打印机安装向导。使用上一步、下一步来切换卡片。

UI界面布局容器与布局策略概述

CardBox可以链接到Tab或一组按钮(例如RadioButton Group),点击时一对一直接切换到对应的卡片页面。

UI界面布局容器与布局策略概述

表格布局 Grids / Table

基于行、列的表格布局,可以将元素按格放置。元素也可以跨行、跨列。元素根据跨行、跨列的定义决定占用的边界,在边界内根据对齐和留白的配置决定位置。

Table.Columns.Add(Column column); 
Table.Rows.Add(Row row);

表格单元格,及跨列放置按钮示意图。

UI界面布局容器与布局策略概述

平铺布局 Tile Layout

下图是Flex4的TileLayout示意图。

UI界面布局容器与布局策略概述

下图是一种较为复杂的网格布局,在平铺布局的基础上有所变化,类似Win8开始菜单出现的磁贴(Tiles)布局。

UI界面布局容器与布局策略概述

工具盒 Toolbox, 工具条 Toolbar, 工具按钮ToolButton

一个工具盒可以容纳多个工具条,每个工具条容纳多个工具按钮

UI界面布局容器与布局策略概述

锚点 Anchor Point - 相对布局 RelativeLayout

锚点布局,如图中的红色方块,设置了锚点后,当窗体大小改变时,被锚定的点会跟随拉伸。

UI界面布局容器与布局策略概述

UI界面布局容器与布局策略概述

停靠面板 DockPanel & 边框布局 Border Layout

两种命名方式下的五个区域名称:

  • DockPanel: Top, Right, Bottom, Left, Fill
  • BorderLayout: North, East, South, West, Center

其中,DockPanel与WinForm完美兼容。可以直接使用。

算法:用添加顺序来决定遮盖方向(每次添加时,在剩余区域内切割一块)

UI界面布局容器与布局策略概述

UI界面布局容器与布局策略概述

手风琴 Accordion

属于分层布局策略,每个层有横向页签展示,相互互斥,一次只展示激活的一层。

UI界面布局容器与布局策略概述

带子 Ribbon

这是现代的新的页签复合样式,适合文档型程序。

UI界面布局容器与布局策略概述

侧边栏 SideBar

侧边栏展示页签,高大上。

UI界面布局容器与布局策略概述

扩展器 Disclosure (Expander)

可以展开折叠的区域,折叠后显示标题文本,展开时可以显示一个扩展面板。

UI界面布局容器与布局策略概述

菜单按钮 MenuButton

MenuButton常见与手机界面,一个面包片按钮代表菜单,当点击时滑出菜单。

UI界面布局容器与布局策略概述

圣杯布局 Holy Grail - 组合布局

圣杯布局是一种组合式布局,是扁平化的经典例子。圣杯布局首先是在网页设计上提出的。

UI界面布局容器与布局策略概述

圣杯布局在不同设备(屏幕和手机)上的变化:

UI界面布局容器与布局策略概述

群组容器 Grouping Container

群组容器用于逻辑上聚集一组UI元素,这些UI元素成为群组容器的子,将随着父容器改变位置、随着父容器隐藏显示改变可用性等。

群组容器其实是一个抽象容器,适合作为容器的基类。从抽象意义上来说,大部分容器都是群组容器的具象。但实际上,我们习惯将一种实线矩形框起来的容器称为群组容器。

在Windows中叫做GroupBox分组框控件。

UI界面布局容器与布局策略概述

GroupBox也有很多扩展实现,包括可复选的标题、可折叠的标题等等。从这个意义上来说,手风琴控件可以看作GroupBox的一个派生类。

点赞
收藏
评论区
推荐文章
blmius blmius
3年前
MySQL:[Err] 1292 - Incorrect datetime value: ‘0000-00-00 00:00:00‘ for column ‘CREATE_TIME‘ at row 1
文章目录问题用navicat导入数据时,报错:原因这是因为当前的MySQL不支持datetime为0的情况。解决修改sql\mode:sql\mode:SQLMode定义了MySQL应支持的SQL语法、数据校验等,这样可以更容易地在不同的环境中使用MySQL。全局s
皕杰报表之UUID
​在我们用皕杰报表工具设计填报报表时,如何在新增行里自动增加id呢?能新增整数排序id吗?目前可以在新增行里自动增加id,但只能用uuid函数增加UUID编码,不能新增整数排序id。uuid函数说明:获取一个UUID,可以在填报表中用来创建数据ID语法:uuid()或uuid(sep)参数说明:sep布尔值,生成的uuid中是否包含分隔符'',缺省为
Wesley13 Wesley13
3年前
java中比较两个时间的差值
项目背景1.某篇文稿的发布时间是publishDate,例如:2020072118:00:41。2.现要求判断该篇文稿的发布时间是否在近30天之内。publicstaticlongdayDiff(DatecurrentDate,DatepublishDate){LongcurrentTimecurrentDat
Stella981 Stella981
3年前
Python之time模块的时间戳、时间字符串格式化与转换
Python处理时间和时间戳的内置模块就有time,和datetime两个,本文先说time模块。关于时间戳的几个概念时间戳,根据1970年1月1日00:00:00开始按秒计算的偏移量。时间元组(struct_time),包含9个元素。 time.struct_time(tm_y
Stella981 Stella981
3年前
Servlet容器,过滤器,拦截器,监听器整理
Servlet容器JavaServlet是与平台无关的服务器端组件,运行于Servlet容器中(如Tomcat),Servlet容器负责Servlet和客户端的通信以及调用Servlet的方法,Servlet和客户端的通信采用“请求/响应”的模式。Servlet可完成以下功能:1、创建并返回基于客户请求的动态HTML页面。2、创建可以嵌入到
Stella981 Stella981
3年前
HTML前端开发之路——弹性盒模型
弹性盒模型(FlexibleBox)是一个CSS3新增布局模块,用于实现容器里项目的对齐、方向、排序;弹性盒模型最大的特效在于,能够动态的修改子元素的宽度和高度,以满足在不同尺寸屏幕下的恰当布局;下面是弹性盒模型的元素基本概念:!(http://static.oschina.net/uploads/space/2016/0212/210
Stella981 Stella981
3年前
Grid布局和Flex布局
Flex布局(弹性布局)Flex是弹性布局,用来为盒状模型提供最大的灵活性,任何一个容器都可以指定为Flex布局。行内元素也可以使用Flex布局。采用Flex布局的元素,称为Flex容器。flexitem项目是Flex布局的元素,简称项目。容器:水平的主轴(mainaxis)和垂直的交叉轴(crossaxis),单个项目占据的主轴空间叫做m
Wesley13 Wesley13
3年前
MySQL部分从库上面因为大量的临时表tmp_table造成慢查询
背景描述Time:20190124T00:08:14.70572408:00User@Host:@Id:Schema:sentrymetaLast_errno:0Killed:0Query_time:0.315758Lock_
Python进阶者 Python进阶者
11个月前
Excel中这日期老是出来00:00:00,怎么用Pandas把这个去除
大家好,我是皮皮。一、前言前几天在Python白银交流群【上海新年人】问了一个Pandas数据筛选的问题。问题如下:这日期老是出来00:00:00,怎么把这个去除。二、实现过程后来【论草莓如何成为冻干莓】给了一个思路和代码如下:pd.toexcel之前把这