Expand description
§Floem
Floem is a cross-platform GUI library for Rust. It aims to be extremely performant while providing world-class developer ergonomics.
The following is a simple example to demonstrate Floem’s API and capabilities.
§Example: Counter
use floem::prelude::*;
let mut counter = RwSignal::new(0);
v_stack((
label(move || format!("Value: {counter}")),
h_stack((
button("Increment").action(move || counter += 1),
button("Decrement").action(move || counter -= 1),
)),
));
This example demonstrates the core concepts of building a reactive GUI with Floem:
- State Management: The
RwSignal
provides a reactive way to manage the counter’s state. - Widgets: Common UI elements like
stack
,label
, andbutton
are easily implemented. - Reactivity: The label automatically updates when the counter changes.
- Event Handling: Button clicks are handled with simple closures that modify the state.
Floem’s objectives prioritize simplicity and performance, enabling the development of complex graphical user interfaces with minimal boilerplate.
§Views
Floem models the UI using a tree of Views. Views, such as the h_stack
, label
, and
button
elements are the building blocks of UI in Floem.
Floem’s main view tree is constructed only once. This guards against unnecessary and expensive rebuilds of your views; however, even though the tree is built only once, views can still receive reactive updates.
§Composition and Flexibility
Views in Floem are composable, allowing for the construction of complex user interfaces by integrating simpler components. In the counter example, label and button views were combined within vertical (v_stack) and horizontal (h_stack) layouts to create a more intricate interface.
This compositional approach provides the following benefits:
- Reusable UI components
- Easy and consistent refactoring
§Learn More
Floem provides a set of built-in views to help you create UIs quickly. To learn more about the built-in views, check out the views module documentation.
§State management
Floem uses a reactive system built on signals and effects for its state management.
Floem uses its own reactive system with an API that is similar to the one in the leptos_reactive crate.
§Signals as State
You can create reactive state by creating a signal anywhere in the program using RwSignal::new()
, RwSignal::new_split()
, or use a different signal type.
When you use a signal by calling the get
or with
methods, (which are also called when you use an operator such as ==
)
the runtime will automatically subscribe the correct side effects
to changes in that signal, creating reactivity. To the programmer this is transparent.
By simply accessing the value where you want to use it, the reactivity will “just work” and
your views will stay in sync with changes to that signal.
§Example: Changing Text
fn app_view() -> impl IntoView {
// All signal types implement `Copy`, so they can be easily used without needing to manually clone them.
let text = RwSignal::new("Hello, World!".to_string());
let label_view = label(move || text.get());
let button = button("Change Text").action(move || text.set("Hello, Floem!".to_string()));
v_stack((button, label_view))
}
In this example, text
is a signal containing a String
that can be both read from and written to.
The button, when clicked, changes the text in the signal.
The label view is subscribed to changes in the text
signal and will automatically trigger a re-render with the updated text value whenever the signal changes.
§Functions as a Primitive of Reactivity
The most fundamental primitive of reactivity is a function that can be re-run in response to changes in a signal.
For this reason, many of Floem’s APIs accept functions as arguments (such as in the label view in the Changing Text
example above).
Most of the functions is Floem’s API will
update reactively, but not all of them do. For this reason, all arguments in Floem’s API that are functions will
be marked with a # Reactivity
section that will inform you if the function will be re-run in response to reactive updates.
§Learn More
To learn more about signals and effects, you may want to explore the Leptos documentation and the leptos book.
§Style: Customizing Appearance
Floem has a powerful, built-in styling system that allows you to customize the appearance of your UI.
Example:
text("Some text").style(|s| s.font_size(21.).color(Color::DARK_GRAY));
The text view is styled by calling the style
method (you’ll need to import the
Decorators
trait to use the it). The style
method takes a closure that takes and returns a
Style
value using the builder pattern. Through this value, you can access methods that modify a variety
of familiar properties such as width, padding, and background. Some Style
properties
such as font size are inherited
and will apply to all of a view’s children until overridden.
In this same style value, floem supports:
- themeing with classes
- property transitions
- defining styles on different interaction states
- reactive updates
- applying styles conditionally
- setting custom properties
- and more
For additional information about styling, see here.
§Animation
In addition to property transitions that can be added to Style
s,
Floem has a full keyframe animation system that allows you to animate any property that can be interpolated and builds on the capabilities and ergonomics of the style system.
Animations in Floem, by default, have keyframes ranging from 0-100.
§Example: Rectangle to Square
empty()
.style(|s| s.background(Color::RED).size(500, 100))
.animation(move |a| {
a.duration(5.seconds())
.keyframe(0, |f| f.computed_style())
.keyframe(50, |f| {
f.style(|s| s.background(Color::BLACK).size(30, 30))
.ease_in()
})
.keyframe(100, |f| {
f.style(|s| s.background(Color::AQUAMARINE).size(10, 300))
.ease_out()
})
.auto_reverse(true)
.repeat(true)
});
- The first keyframe will use the computed style, which will include the red background with size of 500x100.
- At 50%, the animation will animate to a black square of 30x30 with a bezier easing of ease_in.
- At 100% the animation will animate to an aquamarine rectangle of 10x300 with an bezier easing of ease_out.
- The animation is also set to automatically reverse (the animation will run and reverse in 5 seconds) and repeat forever.
You can add aninimations to a View instance by calling the animation
method from the Decorators
trait.
The animation
method takes a closure that takes and returns an Animation
value using the builder pattern.
For additional information about animation, see here.
Re-exports§
pub use window::close_window;
pub use window::new_window;
pub use floem_reactive as reactive;
pub use peniko;
pub use peniko::kurbo;
pub use taffy;
Modules§
- Action functions that can be called anywhere in a Floem application
- Animations
- The Easing trait and the built-in easing functions.
- Style
- Floem built-in Views
Macros§
Structs§
- Encapsulates and owns the global state of the application,
- Floem top level application This is the entry point of the application.
- A ScreenLayout is a snapshot of the layout of a view within a window
- A small unique identifier for an instance of a View.
Enums§
- Delegate enum for
winit
’sUserAttentionType
Traits§
- Converts a value into a
View
. - The View trait contains the methods for implementing updates, styling, layout, events, and painting.
- Extends
WindowId
to give instances methods to retrieve properties of the associated window, much asViewId
does.
Functions§
- Initializes and runs an application with a single window.
- Initiates the application shutdown process.
- Default implementation of
View::layout()
which can be used by view implementations that need the default behavior and also need to implement that method to do additional work.
Type Aliases§
- type erased
View