Floating toolbars
NutrientFloatingToolbar renders the main toolbar’s items as a Material 3 Expressive floating toolbar(opens in a new tab). The user can drag this pill to any edge of the window. The pill lays out horizontally at the top or bottom and vertically at a side, and it moves with spring animation. NutrientFloatingContextualToolbar does the same for the contextual toolbar that’s currently shown. Both read from the ToolbarCoordinator, so the items, their state, and the SDK’s handling of taps are identical to the docked bars.
Use them in a Compose host that draws its own chrome around DocumentView. They’re alternatives to the docked NutrientMainToolbar and NutrientContextualToolbar, not replacements. The toolbars that the SDK mounts itself stay docked.
Basic usage
Turn off both of the SDK’s toolbars and compose the pills over the document:
val configuration = PdfActivityConfiguration.Builder(context) .defaultToolbarEnabled(false) .defaultContextualToolbarEnabled(false) .build()val documentState = rememberDocumentState(uri, configuration)val coordinator by documentState.toolbarCoordinator.collectAsState()
Box(Modifier.fillMaxSize()) { DocumentView(documentState = documentState, modifier = Modifier.fillMaxSize()) coordinator?.let { c -> NutrientFloatingToolbar(coordinator = c) NutrientFloatingContextualToolbar(coordinator = c) }}The main pill starts docked at the bottom. It follows the viewer’s user interface visibility, so it slides away in immersive mode. The contextual pill appears when the user enters a mode and disappears when the user leaves it. The Catalog app’s MainToolbarFloatingExample shows both.
Where the pill docks
A FloatingToolbarState holds the pill’s current edge. Its allowedEdges limit where the user can drop the pill after a drag. Create it with rememberFloatingToolbarState, which keeps the state through configuration changes and process death:
val state = rememberFloatingToolbarState( initialEdge = FloatingToolbarEdge.Bottom, allowedEdges = setOf(FloatingToolbarEdge.Top, FloatingToolbarEdge.Bottom), // never a side rail.)NutrientFloatingToolbar(coordinator = c, state = state)
// Move it yourself:state.dockTo(FloatingToolbarEdge.Top)FloatingToolbarEdge is Top, Bottom, Start, or End. Start and End are logical edges, so they swap sides in a right-to-left layout. state.isDragging and state.previewedEdge report a drag in progress, so other chrome can react to it. Pass draggable = false to pin the pill in place.
The contextual pill also follows the bar’s allowed docks and close button placement. A bar that the SDK restricts to the top therefore never becomes a side rail.
Collapsing
With collapsible = true, the main pill shrinks to its active item after a tap and expands again on the next tap:
NutrientFloatingToolbar(coordinator = c, state = state, collapsible = true)
state.collapse()state.expand()state.isExpanded // observe.state.activeItemId // the item the collapsed pill shows.Appearance
The pill takes its colors from the Material 3 floating toolbar color roles of the host’s MaterialTheme. With vibrant = true (the default), the pill uses primaryContainer with vibrant icon button colors. With vibrant = false, it uses the standard variant on surfaceContainer. The roles tint the icons, so a tint baked into a ToolbarIcon.Resource or ToolbarIcon.Vector is ignored. ToolbarIcon.Composed content renders as is. A selected item, such as the item of an open outline or an active tool, renders with a filled primary container. Items declared with OverflowBehavior.Never stay in the pill’s overflow menu, and items that don’t fit follow them there.
While inline search is active, the pill hides, and a full-width search pill springs in at the top edge. The search pill takes its colors from the ambient Material 3 color scheme.
The pill reads windowInsets (default WindowInsets.safeDrawing) to stay clear of the system bars and the display cutout on whichever edge it docks to.
Building your own pill
The SDK’s pills are built from public components. A host that wants to arrange the same items differently can use them directly:
NutrientFloatingToolbarItemButton(item, vibrant, edge, onAction)renders one item as a Material 3 icon button with the selected fill. It also adds a submenu dropdown for aToolbarItem.Submenuand a tooltip that opens away fromedge.NutrientFloatingToolbarMenuItem(item, onClick)renders an item as a row in a dropdown menu, such as an overflow menu.NutrientFloatingToolbarSearchTheme { … }provides the Material-derived colors that the SDK’s inline search bar uses inside a pill. ANutrientToolbarSearchBar(coordinator)composed inside it then matches the pill.
val items by c.items.collectAsState()Row { items.visible.forEach { item -> NutrientFloatingToolbarItemButton(item = item, edge = FloatingToolbarEdge.Bottom, onAction = c::dispatch) }}Dispatching the action back to the coordinator is what makes the SDK handle the tap. The Catalog app’s MainToolbarFabMenuExample uses these pieces to build a Material 3 Expressive floating action button (FAB) menu. The collapsed FAB shows the active item. Tapping it expands a labeled list of actions, and a long press drags it between the bottom corners.
Status bar scrim
A floating pill sits below the status bar. Unlike the SDK’s edge-to-edge toolbar, it leaves the strip above it uncovered, so the document scrolls under the clock and system icons. NutrientDocumentStatusBarScrim covers that strip with a tint and, on API 31 and later, a blur. It samples the document through a backdrop that the DocumentView records into:
val backdrop = rememberNutrientBackdropState()
Box(Modifier.fillMaxSize()) { // Must draw before the scrim: the scrim samples whatever drew before it. DocumentView( documentState = documentState, modifier = Modifier.fillMaxSize().nutrientBackdropSource(backdrop), ) NutrientDocumentStatusBarScrim( documentState = documentState, state = backdrop, modifier = Modifier.align(Alignment.TopCenter), ) coordinator?.let { NutrientFloatingToolbar(coordinator = it) }}The scrim stays hidden while the SDK’s own toolbar is mounted and while the viewer is in immersive mode. It appears only once the page scrolls up into the strip, and it fades in over the first part of the strip. The default tint follows the window’s status bar icon appearance: translucent white under dark icons and translucent black under light icons. color and blurRadius override the defaults, which live in NutrientStatusBarScrimDefaults. NutrientStatusBarScrim is the same scrim with an explicit visible flag, for chrome that a DocumentState doesn’t drive. In PdfActivity and nutrientToolbarsComposeView hosts, the document is a sibling View that can’t be sampled, so the scrim falls back to a flat tint there.
API
These are the signatures of NutrientFloatingToolbar and NutrientFloatingContextualToolbar. The table after them describes each parameter and its default:
@Composablefun NutrientFloatingToolbar( coordinator: ToolbarCoordinator, modifier: Modifier = Modifier, state: FloatingToolbarState = rememberFloatingToolbarState(), vibrant: Boolean = true, draggable: Boolean = true, collapsible: Boolean = false, windowInsets: WindowInsets = WindowInsets.safeDrawing,)
@Composablefun NutrientFloatingContextualToolbar( coordinator: ToolbarCoordinator, modifier: Modifier = Modifier, state: FloatingToolbarState = rememberFloatingToolbarState(), vibrant: Boolean = true, draggable: Boolean = true, defaultGroupingProvider: ContextualToolbarGroupingProvider? = null, windowInsets: WindowInsets = WindowInsets.safeDrawing,)| Parameter | Default | What it does |
|---|---|---|
coordinator | The ToolbarCoordinator the pill renders. | |
state | rememberFloatingToolbarState() | Current edge, allowed edges, and expansion; saved across configuration changes. |
vibrant | true | Vibrant or standard Material 3 floating toolbar colors. |
draggable | true | Whether the user can drag the pill between edges. |
collapsible | false | Main pill only: shrink to the active item after a tap. |
defaultGroupingProvider | null | Contextual pill only: grouping when none is registered on the coordinator. |
windowInsets | WindowInsets.safeDrawing | Insets the pill keeps clear of on the edge it docks to. |
Related
- Main toolbar and contextual toolbar — The docked composables.
- Toolbar hosting — The coordinator and the inset model.
- Main toolbar — Customizing the items the pill shows.
- Catalog app —
MainToolbarFloatingExample,MainToolbarFabMenuExample, andMainToolbarCustomizationExample.