概述
Ratatui
中的坐标系从左到右,从上到下,原点 (0, 0)
位于终端的左上角。x
和y
坐标由u16
值表示,如下图所示。
布局和小部件构成了Ratatui
中UI的基础。布局决定了界面的结构,使用约束将屏幕划分为不同的部分,而小部件则用内容填充这些部分。
在将小部件呈现到屏幕上时,首先需要定义小部件将显示的区域。此区域在缓冲区中由具有特定高度和宽度的矩形表示。可以将此矩形指定为绝对位置和大小,也可以使用 Layout
结构体根据 Length
、 Min
、 Max
、 Ratio
、 Percentage
等约束动态划分终端窗口。
The Layout struct
使用布局结构的一个简单示例:
use ratatui::prelude::*;
let layout = Layout::default()
.direction(Direction::Vertical) //指定布局方向为垂直
.constraints(vec![//约束集
Constraint::Percentage(50),//添加一个约束,占比50%
Constraint::Percentage(50),
])
.split(frame.size());//使用split进行分割
在这个例子中,我们希望将可用空间垂直地分成两个相等的部分,每个部分分配50%的屏幕高度。 Layout::split
函数将终端窗口的总大小作为参数(由 Frame::size()
方法返回),然后根据指定的约束为每个矩形计算适当的大小和位置。
一旦定义了布局,就可以使用从此布局派生的矩形区域之一来呈现小部件。这可以通过调用 Frame::render_widget
或 frame::render_stateful_widget
方法来实现:
frame.render_widget(
Paragraph::new("Top")
.block(Block::new().borders(Borders::ALL)),
layout[0]);
frame.render_widget(
Paragraph::new("Bottom")
.block(Block::new().borders(Borders::ALL)),
layout[1]);
渲染结果如下
嵌套布局
布局可以嵌套。这意味着您可以在外部布局的矩形内定义另一个布局。这种嵌套布局允许构建复杂而灵活的UI
设计,同时仍然可以控制窗口小部件网格如何随终端窗口调整大小。来看一个示例
// 先定义一个外部布局
let outer_layout = Layout::default()
.direction(Direction::Vertical)
.constraints(vec![
Constraint::Percentage(50),
Constraint::Percentage(50),
])
.split(f.size());
// 定义内部布局,并将其嵌入外部布局的某一区域
let inner_layout = Layout::default()
.direction(Direction::Horizontal)
.constraints(vec![
Constraint::Percentage(25),
Constraint::Percentage(75),
])
.split(outer_layout[1]);//split接收一个Rect参数,即布局要嵌入的区域
下面在该嵌套布局中渲染组件
frame.render_widget(
Paragraph::new("outer 0")
.block(Block::new().borders(Borders::ALL)),
outer_layout[0]);
frame.render_widget(
Paragraph::new("inner 0")
.block(Block::new().borders(Borders::ALL)),
inner_layout[0]);
frame.render_widget(
Paragraph::new("inner 1")
.block(Block::new().borders(Borders::ALL)),
inner_layout[1]);
渲染结果如下
Constraints
Constraints
规定了布局中组件的大小和排列。Ratatui
框架提供了几种用于微调用户界面布局的约束类型:
Constraint::Length(u16)
:此约束指定矩形应占用的特定行数或列数。这是由绝对大小决定的,不会随终端大小缩放而改变。Constraint::Percentage(u16)
:此约束提供相对于父布局或终端窗口本身大小的大小。例如,Constraint::Percentage(50)
表示一个矩形应该占据其父矩形大小的50%。Constraint::Ratio(u16, u16)
:利用占比可以更精细地分割布局。例如,Constraint::Ratio(1, 3)
将分配父级大小的1/3给此约束。Constraint::Min(u16)
:限制区域的最小值,不论区域如何缩小,也会保证该区域有最小宽度/高度。Constraint::Max(u16)
:限制区域的最打值,不论区域如何放大,也会保证该区域有最大宽度/高度。
Constraints
可以在布局中混合和匹配,以创建动态和可调整的界面。在定义应用程序的布局时,可以使用这些约束:
let layout = Layout::default()
.direction(Direction::Horizontal)//布局水平排列
.constraints([
Constraint::Length(10),//占10个字符宽度
Constraint::Percentage(70),//占比70%
Constraint::Min(5),//最小占5个字符宽度
]
.into_iter())
.split(frame.size());
在本例中,初始 Length
约束使第一个矩形的宽度为10个字符。下一个矩形将占总宽度的70%。最后的矩形将占用剩余的空间,但永远不会小于5个字符。
边框会占据一个字符宽度,满足10字符宽度,70%占比,最小5字符宽度的约束,缩放至最小宽度
也符合约束要求。