Alignment
When arranging elements in stacks, placement ambiguity can arise when the child views differ in length along the axis opposite to the arrangement axis.
Vertical stacks can have horizontal alignment ambiguity, and horizontal stacks can have vertical alignment ambiguity.
In the previous example, the HStack
height resolved to the full window height
because Rectangle
takes height greedily. But the Circle
frame is shorter
so Buoyant needs to make a decision about where to place it. This ambiguity was
resolved using the default, Center
, but you can change it by calling
.with_alignment()
on the stack.
If you wanted to align the Circle
from the previous example to the top edge,
you could set VerticalAlignment::Top
.
extern crate buoyant; extern crate embedded_graphics; extern crate embedded_graphics_simulator; use buoyant::{ environment::DefaultEnvironment, layout::Layout, render::{EmbeddedGraphicsRender as _, Renderable as _}, }; use embedded_graphics::{pixelcolor::Rgb888, prelude::*}; use embedded_graphics_simulator::{OutputSettings, SimulatorDisplay, Window}; const BACKGROUND_COLOR: Rgb888 = Rgb888::CSS_DARK_SLATE_GRAY; const DEFAULT_COLOR: Rgb888 = Rgb888::WHITE; fn main() { let mut window = Window::new("Example", &OutputSettings::default()); let mut display: SimulatorDisplay<Rgb888> = SimulatorDisplay::new(Size::new(480, 320)); display.clear(BACKGROUND_COLOR).unwrap(); let environment = DefaultEnvironment::default(); let origin = buoyant::primitives::Point::zero(); let view = view(); let layout = view.layout(&display.size().into(), &environment); let render_tree = view.render_tree(&layout, origin, &environment); render_tree.render(&mut display, &DEFAULT_COLOR, origin); window.show_static(&display); } use buoyant::layout::VerticalAlignment; use buoyant::view::shape::{Circle, Rectangle}; use buoyant::view::HStack; use buoyant::view::RenderExtensions as _; use buoyant::render::EmbeddedGraphicsView; fn view() -> impl EmbeddedGraphicsView<Rgb888> { HStack::new(( Circle.foreground_color(Rgb888::CSS_CORAL), Rectangle .corner_radius(25) .foreground_color(Rgb888::CSS_DARK_ORCHID), )) .with_alignment(VerticalAlignment::Top) }
You'll see this ambiguity arise again with ZStack
and the frame modifiers.
A note on how SwiftUI alignment differs
If you're coming from SwiftUI, your understanding of alignment is most likely a bit wrong. This is probably fine, and conveniently, if you're wrong about SwiftUI you probably already have the correct understanding of alignment in Buoyant!
I think it's worth briefly explaining how SwiftUI alignment actually works and what that means for special alignments you can't build (yet) in Buoyant. Feel free to skip this if you're totally new to both and feeling lost.
Using HStack as an example, when you specify .bottom
vertical alignment in SwiftUI you are
not telling the HStack to align all the children to the bottom edge of the stack. You are
telling it to align the .bottom
alignment guides of all the children. Each child view
reports a set of named marks, called alignment guides, which the stack uses for alignment.
While generally you can assume .top
is placed at y = 0 and .bottom
is placed at y =
frame.height, views are free to place these guides wherever they want. The stack simply
lines up the mark across all the children. Custom marks are even preserved when nesting
views inside other modifiers.
This is especially useful when you have a horizontal stack containing text of multiple sizes. You can tell SwiftUI to align the text baselines, giving a much more visually appealing result.
Buoyant does not have this feature, but I recognize the utility it provides. For now, you can only align to the center and outer edges. Thinking about alignment in terms of "Top aligns views to the top" is correct for Buoyant.