waterui-layout
Layout building blocks for arranging views in WaterUI applications.
Overview
waterui-layout provides the fundamental layout primitives used to compose user interfaces in WaterUI. Unlike traditional UI frameworks that manually calculate positions, this crate implements a declarative, constraint-based layout system inspired by SwiftUI's layout protocol. All components render to native platform widgets (UIKit/AppKit on Apple, Android View on Android) rather than drawing custom pixels.
The crate bridges the declarative View trait with the imperative, backend-driven layout pass through the Layout trait, enabling flexible composition of stacks, spacers, frames, and scrollable containers. All layout values use logical pixels (points/dp) matching design tool specifications exactly, with native backends handling density-aware conversion to physical pixels.
Installation
Add this to your Cargo.toml:
[]
= "0.1.0"
Or use the main waterui crate which re-exports all layout components:
[]
= "0.2"
Quick Start
Here's a simple toolbar layout demonstrating horizontal stacking and spacers:
use ;
use text;
use View;
This creates a horizontal layout with "WaterUI" on the left, "v0.1" on the right, and flexible space between them.
Core Concepts
Layout Trait
The Layout trait defines how containers arrange their children through a two-phase protocol:
- Sizing Phase:
size_that_fits(proposal, children)determines the container's size given a parent proposal - Placement Phase:
place(bounds, children)positions children within the final bounds
Layouts can query children multiple times with different proposals to negotiate optimal sizing.
Stretch Behavior
Views communicate their flexibility through StretchAxis:
None- Content-sized, uses intrinsic dimensionsHorizontal- Expands width only (e.g., TextField)Vertical- Expands height onlyBoth- Greedy, fills all space (e.g., Spacer, Color)MainAxis- Stretches along parent's main axis (used by Spacer)CrossAxis- Stretches along parent's cross axis (used by Divider)
Stack containers distribute remaining space among stretching children proportionally.
Logical Pixels
All layout values use logical pixels (points/dp) - the same unit as Figma, Sketch, and Adobe XD:
spacing(8.0)= 8pt in design toolswidth(100.0)= 100pt/dp, same physical size across all devices- iOS/macOS: Uses points natively
- Android: Converts dp → pixels via
displayMetrics.density
This ensures pixel-perfect design implementation across platforms.
Examples
Building a Form Layout
use ;
use text;
use TextField;
use binding;
use View;
Creating a Toolbar with Spacers
use ;
use button;
use text;
use View;
Overlaying Content
use ;
use Color;
use text;
use View;
Scrollable Content
use ;
use text;
use View;
Responsive Layout with Frames
use Frame;
use Alignment;
use text;
use View;
API Overview
Stack Containers
-
stack::hstack(content)- Arranges children horizontally left-to-right.spacing(f32)- Sets spacing between children.alignment(VerticalAlignment)- Sets vertical alignment (Top, Center, Bottom)
-
stack::vstack(content)- Arranges children vertically top-to-bottom.spacing(f32)- Sets spacing between children.alignment(HorizontalAlignment)- Sets horizontal alignment (Leading, Center, Trailing)
-
stack::zstack(content)- Overlays children in the same space.alignment(Alignment)- Sets 2D alignment for overlaid content
Layout Primitives
-
spacer()- Flexible space that expands to push views apart -
spacer_min(f32)- Spacer with minimum length -
ScrollView- Scrollable container for overflow contentscroll(content)- Vertical scrollingscroll_horizontal(content)- Horizontal scrollingscroll_both(content)- Bidirectional scrolling
-
Frame- Constrains child size with min/max/ideal dimensions.width(f32),.height(f32)- Sets ideal dimensions.min_width(f32),.max_width(f32)- Sets size constraints.alignment(Alignment)- Aligns child within frame
-
Padding- Insets child with edge spacingEdgeInsets::all(f32)- Equal padding on all edgesEdgeInsets::symmetric(vertical, horizontal)- Symmetric paddingEdgeInsets::new(top, bottom, leading, trailing)- Custom edges
Advanced Layouts
overlay(base, layer)- Layers content on top of base without affecting layout sizeOverlayLayout- Layout engine where base child dictates container sizeLazyContainer- Efficient container for dynamic collections withForEachIgnoreSafeArea- Metadata to extend content into safe area regionsEdgeSet- Bitflags for specifying which edges ignore safe area
Alignment Types
Alignment- 2D alignment (TopLeading, Top, TopTrailing, Leading, Center, Trailing, BottomLeading, Bottom, BottomTrailing)HorizontalAlignment- Leading, Center, TrailingVerticalAlignment- Top, Center, BottomAxis- Horizontal, Vertical (for stack direction)
Features
This crate supports optional features:
serde- Enables serialization/deserialization of layout types via serde
Enable features in your Cargo.toml:
[]
= { = "0.1.0", = ["serde"] }
Architecture Notes
Backend Integration
Layouts communicate with native backends through the Layout trait's protocol:
- Backend calls
size_that_fits(proposal, children)to measure - Backend calls
place(bounds, children)to get child rectangles - Backend renders native widgets at the calculated positions
The FFI layer in waterui-ffi handles the Rust ↔ Native boundary.
Performance Characteristics
- All layout calculations happen in Rust, then native backends cache results
- The
SubViewtrait enables measurement caching at the platform level - Lazy containers (
LazyContainer) defer child instantiation for large collections - Layout is pure (no side effects), enabling aggressive optimization by backends
Layout Compression
When children exceed available space:
- HStack: Compresses largest non-stretching children first, preserving small labels
- VStack: Children maintain intrinsic heights, may overflow bounds (scrollable)
- Minimum size enforcement prevents unreadable content (20pt minimum for compressed children)
This behavior matches native platform conventions for graceful degradation.