ResizableSplitter class
A high-performance resizable splitter widget with robust pointer handling.
- Smooth dragging, keyboard navigation, and accessible semantics.
- Works with embedded platform views (e.g., WebViews) via an overlay shield to stop pointer events from being stolen.
- Extensive customization via divider (SplitterDividerStyle): a state-dependent color, thickness, grab slop, and a custom grip builder.
If the incoming constraints along axis are unbounded or zero, the splitter cannot resize, so under the default UnboundedBehavior.shrinkToChildren it shows the two panels without the divider, sized to their content. Opt into UnboundedBehavior.useFallbackExtent (via ResizableSplitterTheme or the constructor) to give the handle a finite sandbox while preserving side panels.
Theme precedence: explicit constructor values override
ResizableSplitterTheme, which in turn overrides
Theme.of(context).extension<ResizableSplitterThemeData>(). Every theme
field is nullable, so a partial override only replaces the fields it sets.
When nothing is provided, colors fall back to the ambient ThemeData
(via ColorScheme) and numeric values fall back to the defaults documented
on each parameter.
- Inheritance
-
- Object
- DiagnosticableTree
- Widget
- StatefulWidget
- ResizableSplitter
Constructors
-
ResizableSplitter({required Widget start, required Widget end, Key? key, SplitterController? controller, Axis axis = Axis.horizontal, SplitterPosition initialPosition = const SplitterPosition.fraction(0.5), SplitterPaneConstraints startConstraints = const SplitterPaneConstraints(minExtent: 100), SplitterPaneConstraints endConstraints = const SplitterPaneConstraints(minExtent: 100), double minStartFraction = 0.0, double maxStartFraction = 1.0, SplitterDividerStyle? divider, ValueChanged<
SplitterChangeDetails> ? onChanged, ValueChanged<SplitterChangeDetails> ? onChangeStart, ValueChanged<SplitterChangeDetails> ? onChangeEnd, bool? enableKeyboard, bool? enableHaptics, double? keyboardStep, double? pageStep, String? semanticsLabel, SplitterSemanticsLabels? semantics, Color? dragBarrierColor, Widget dragBarrierBuilder(BuildContext context)?, bool? shieldPlatformViews, SplitterSnapBehavior? snap, bool holdScrollWhileDragging = false, bool deferredResize = false, double? doubleTapResetTo, bool resizable = true, VoidCallback? onHandleTap, VoidCallback? onHandleDoubleTap, SplitterConstraintPolicy constraintPolicy = SplitterConstraintPolicy.favorStart, SplitterSurplusPolicy surplusPolicy = SplitterSurplusPolicy.leaveGap, UnboundedBehavior? unboundedBehavior, double? fallbackExtent, bool? snapToPhysicalPixels, String? restorationId}) -
Builds a resizable splitter with the provided panels and configuration.
const
Properties
- axis → Axis
-
The axis along which to split (horizontal or vertical).
final
- constraintPolicy → SplitterConstraintPolicy
-
Policy applied when both panes cannot meet their minimums at once
(a shortage).
final
- controller → SplitterController?
-
Optional controller for programmatic control and persistence.
final
- deferredResize → bool
-
Defers the resize until the drag is released. While dragging, the panes
keep their committed size and a lightweight preview line tracks the
pointer; on release the panes settle to the final position once. Useful
when the panes contain expensive subtrees. Defaults to false (live resize).
final
- divider → SplitterDividerStyle?
-
Divider appearance and grab configuration: thickness, a state-dependent
color, the SplitterDividerStyle.interactiveExtent grab target, and a
custom grip SplitterDividerStyle.builder. Unset fields fall back to
ResizableSplitterTheme, then to the built-in defaults.
final
- doubleTapResetTo → double?
-
Optional ratio to jump to on double-tap.
final
- dragBarrierBuilder → Widget Function(BuildContext context)?
-
Builds the visual of the drag barrier shown while dragging. The shield
itself is kept regardless - an opaque hit blocker plus an always-painted
base layer that composites a Flutter surface above platform views so they
can't swallow the pointer release and strand the drag. This only customizes
what is drawn on top of that base (the default is a dragBarrierColor
fill, or nothing). Only used when shieldPlatformViews is enabled.
final
- dragBarrierColor → Color?
-
The drag barrier's fill color while dragging. Ignored if
dragBarrierBuilder is set. Leave it null for the default: the shield
still paints an imperceptible base layer (so it composites above platform
views and the OS can't route the release to a native view), just with no
visible tint.
final
- enableHaptics → bool?
-
Whether haptic feedback fires on drag start and keyboard adjustments.
final
- enableKeyboard → bool?
-
Whether to enable keyboard navigation with arrow keys. Defaults to true.
final
- end → Widget
-
The widget to display in the end position (right/bottom).
final
- endConstraints → SplitterPaneConstraints
-
Pixel sizing limits for the end (right/bottom) pane. Defaults to a 100px
minimum.
final
- fallbackExtent → double?
-
Extent in pixels to use when unboundedBehavior is
UnboundedBehavior.useFallbackExtent. Defaults to 500.
final
- hashCode → int
-
The hash code for this object.
no setterinherited
- holdScrollWhileDragging → bool
-
Whether to temporarily hold the nearest Scrollable's position while dragging.
final
- initialPosition → SplitterPosition
-
Initial split position if no controller is provided. Use
SplitterPosition.startPixels / SplitterPosition.endPixels to pin a pane
to a pixel width that survives container resizes, or
SplitterPosition.fraction for a ratio. Defaults to a centered fraction.
final
- key → Key?
-
Controls how one widget replaces another widget in the tree.
finalinherited
- keyboardStep → double?
-
Step applied with Arrow keys (e.g., 0.01 = 1%). Defaults to 0.01.
final
- maxStartFraction → double
-
Highest fraction of the available space the start pane may take (0.0-1.0).
final
- minStartFraction → double
-
Lowest fraction of the available space the start pane may take (0.0-1.0).
final
-
onChanged
→ ValueChanged<
SplitterChangeDetails> ? -
Called as the divider moves through an interaction or a collapse, with both
the request and the resolved layout plus the SplitterChangeSource.
final
-
onChangeEnd
→ ValueChanged<
SplitterChangeDetails> ? -
Called when a drag gesture ends, balancing every onChangeStart with
exactly one end so a consumer can pair them (e.g. to clear a "dragging"
flag). SplitterChangeDetails.end reports how it ended:
SplitterChangeEnd.committed for a normal release (the source is
SplitterChangeSource.snap when a snap point claimed it) or
SplitterChangeEnd.canceled for a system cancel (nothing is committed).
The one unbalanced case is a drag force-ended by reconfiguring or disposing
the splitter mid-gesture, which fires no end.
final
-
onChangeStart
→ ValueChanged<
SplitterChangeDetails> ? -
Called when a drag gesture starts, with the position at that moment - the
real request, which may be a pixel pin.
final
- onHandleDoubleTap → VoidCallback?
-
Called when the divider is double-tapped.
final
- onHandleTap → VoidCallback?
-
Called when the divider is tapped.
final
- pageStep → double?
-
Step applied with PageUp/PageDown keys (e.g., 0.1 = 10%). Defaults to 0.1.
final
- resizable → bool
-
Whether the divider responds to drag gestures.
final
- restorationId → String?
-
Restoration id for persisting the divider position across app restarts.
final
- runtimeType → Type
-
A representation of the runtime type of the object.
no setterinherited
- semantics → SplitterSemanticsLabels?
-
Localizable semantics strings and value formatting. Unset fields fall back
to ResizableSplitterTheme, then to the built-in English defaults. Set it
app-wide via the theme to localize every splitter at once.
final
- semanticsLabel → String?
-
Accessibility label for the divider. Overrides the label resolved from
semantics (or the ambient theme) when set, leaving the value formatting
intact - a quick way to relabel a single splitter without supplying a full
SplitterSemanticsLabels.
final
- shieldPlatformViews → bool?
-
Whether the protective overlay is used while dragging. Defaults to true.
final
- snap → SplitterSnapBehavior?
-
Optional snap behavior for the divider, or null for no snapping.
final
- snapToPhysicalPixels → bool?
-
Floors the leading panel size to whole physical pixels to avoid anti-alias
gaps. Defaults to false.
final
- start → Widget
-
The widget to display in the start position (left/top).
final
- startConstraints → SplitterPaneConstraints
-
Pixel sizing limits for the start (left/top) pane. Defaults to a 100px
minimum. Set SplitterPaneConstraints.maxExtent to cap the pane, or
SplitterPaneConstraints.collapsible to allow collapsing.
final
- surplusPolicy → SplitterSurplusPolicy
-
Policy applied when both panes' maximums are too small to fill the space
(a surplus). Defaults to SplitterSurplusPolicy.leaveGap, which keeps
SplitterPaneConstraints.maxExtent a true maximum (the leftover becomes a
gap between the panes rather than overflowing one past its maximum).
final
- unboundedBehavior → UnboundedBehavior?
-
Fallback layout behavior when constraints are unbounded along the main
axis. Defaults to UnboundedBehavior.shrinkToChildren.
final
Methods
-
createElement(
) → StatefulElement -
Creates a StatefulElement to manage this widget's location in the tree.
inherited
-
createState(
) → State< ResizableSplitter> -
Creates the mutable state for this widget at a given location in the tree.
override
-
debugDescribeChildren(
) → List< DiagnosticsNode> -
Returns a list of DiagnosticsNode objects describing this node's
children.
inherited
-
debugFillProperties(
DiagnosticPropertiesBuilder properties) → void -
Add additional properties associated with the node.
override
-
noSuchMethod(
Invocation invocation) → dynamic -
Invoked when a nonexistent method or property is accessed.
inherited
-
toDiagnosticsNode(
{String? name, DiagnosticsTreeStyle? style}) → DiagnosticsNode -
Returns a debug representation of the object that is used by debugging
tools and by DiagnosticsNode.toStringDeep.
inherited
-
toString(
{DiagnosticLevel minLevel = DiagnosticLevel.info}) → String -
A string representation of this object.
inherited
-
toStringDeep(
{String prefixLineOne = '', String? prefixOtherLines, DiagnosticLevel minLevel = DiagnosticLevel.debug, int wrapWidth = 65}) → String -
Returns a string representation of this node and its descendants.
inherited
-
toStringShallow(
{String joiner = ', ', DiagnosticLevel minLevel = DiagnosticLevel.debug}) → String -
Returns a one-line detailed description of the object.
inherited
-
toStringShort(
) → String -
A short, textual description of this widget.
inherited
Operators
-
operator ==(
Object other) → bool -
The equality operator.
inherited