The ImageViewer component loads and displays images from various sources with automatic loading indicators.
Basic Usage
use freya::prelude::*;
fn app() -> impl IntoElement {
let image: ImageSource = "https://example.com/image.jpg".into();
ImageViewer::new(image)
}
Image Sources
Remote URL
Load images from the web (requires remote-asset feature):
let source: ImageSource = "https://example.com/image.jpg".into();
ImageViewer::new(source)
File Path
Load images from the filesystem:
use std::path::PathBuf;
let source: ImageSource = PathBuf::from("./images/photo.png").into();
ImageViewer::new(source)
Embedded Bytes
Embed images directly in the binary:
let source: ImageSource = (
"my-image", // Unique identifier
include_bytes!("./assets/logo.png")
).into();
ImageViewer::new(source)
Properties
Image source (URL, path, or bytes)
Plus all standard layout and styling properties:
width(), height()
corner_radius()
a11y_alt() - Alternative text for accessibility
- And more via
LayoutExt, ImageExt, AccessibilityExt
ImageSource
The ImageSource enum supports three types:
pub enum ImageSource {
Uri(Uri), // Remote (requires remote-asset feature)
Path(PathBuf), // Local file
Bytes(&'static str, Bytes), // Embedded
}
Complete Example
use freya::prelude::*;
use std::path::PathBuf;
fn app() -> impl IntoElement {
let remote = "https://images.example.com/photo.jpg";
let local = PathBuf::from("./assets/logo.png");
let embedded = ("icon", include_bytes!("./assets/icon.png"));
rect()
.horizontal()
.spacing(16.)
.child(
ImageViewer::new(remote)
.width(Size::px(200.))
.height(Size::px(200.))
.a11y_alt("A beautiful photo")
)
.child(
ImageViewer::new(local)
.width(Size::px(200.))
.height(Size::px(200.))
)
.child(
ImageViewer::new(embedded)
.width(Size::px(64.))
.height(Size::px(64.))
)
}
Loading States
ImageViewer automatically handles loading states:
- Pending: Initial state
- Loading: Fetching/decoding the image (shows loader)
- Cached: Image loaded successfully (displays image)
- Error: Failed to load (displays error message)
// Shows CircularLoader while loading
ImageViewer::new("https://example.com/large-image.jpg")
Sizing
Control image dimensions:
// Fixed size
ImageViewer::new(source)
.width(Size::px(300.))
.height(Size::px(200.))
// Percentage
ImageViewer::new(source)
.width(Size::percent(50.))
.height(Size::percent(50.))
// Fill container
ImageViewer::new(source)
.width(Size::fill())
.height(Size::fill())
Corner Radius
Round the corners:
ImageViewer::new(source)
.width(Size::px(100.))
.height(Size::px(100.))
.corner_radius(50.) // Circle
Accessibility
Provide alternative text for screen readers:
ImageViewer::new(source)
.a11y_alt("Company logo")
.a11y_role(AccessibilityRole::Image)
Image Gallery
Create a responsive image gallery:
let images = vec![
"https://example.com/1.jpg",
"https://example.com/2.jpg",
"https://example.com/3.jpg",
];
ScrollView::new().child(
rect()
.direction(Direction::Horizontal)
.spacing(12.)
.children(
images.into_iter().map(|url| {
ImageViewer::new(url)
.width(Size::px(200.))
.height(Size::px(200.))
.corner_radius(8.)
.into()
})
)
)
Lazy Loading
Images are loaded asynchronously and cached:
// Multiple instances with same source share the cached image
rect()
.horizontal()
.child(ImageViewer::new("https://example.com/image.jpg"))
.child(ImageViewer::new("https://example.com/image.jpg")) // Uses cache
- Images are fetched asynchronously
- Automatic caching prevents duplicate downloads
- Efficient image decoding with Skia
- Loading indicators prevent layout shifts
Error Handling
If an image fails to load, the error message is displayed:
ImageViewer::new("https://invalid-url.com/missing.jpg")
// Will show: "Failed to load image: ..."
Supports common image formats:
- PNG
- JPEG
- GIF
- WebP
- BMP
- ICO
Source
View the full implementation: image_viewer.rs