assorted_layout_widgets
Widgets SideBySide, RowProportional, AnimatedBetween, Box, Pad, Delayed, WrapSuper, OtpCodeVerificationField, ButtonBarSuper, NormalizedOverflowBox, showDialogSuper and much more.
12.12.1
66K downloads/mo
#1308 most downloaded on pub.dev
marcglasberg/assorted_layout_widgets
What this package is like to depend on
Last release 17 days ago
06 Aug 2026
Ships unpredictably
gaps range from 9 days to 1.1 years
Some releases are documented
notes for 66 of 127 stable releases
Nothing withdrawn
no release was ever pulled
7 years old
131 releases · first in 2019
21 releases in the last 12 months
see the full history below
Release timeline
131 releases · Nov 2019 to Aug 2026Releases
latest 60 of 131-
12.12.106 Aug 2026Release notes
Open source →-
The new
SquircleBorderclass is similar to Flutter'sContinuousRectangleBorder, but it allows more configuration options. It defines a rounded-rectangle shape (like a "squircle") where two things are chosen independently: how big the corners are, and how the corner curve looks.
-
-
12.12.006 Aug 2026Nothing published for this version
-
12.11.004 Aug 2026Release notes
Open source →- New
KeyboardparametercloseOnTapOnlyIfKeyboardIsOpen(defaultfalse). Whentrue, the close-on-tap behavior (iOsCloseOnTap/androidCloseOnTap) acts only when the system keyboard is actually open: while it's closed, tapping an empty area of the screen does nothing.
- New
-
12.10.029 Jul 2026Release notes
Open source →- New
TimeBuilder.eachconstructor, which rebuilds once for each givenintervalof time:TimeBuilder.each(interval: const Duration(seconds: 5), builder: ...)rebuilds each 5 seconds. The ticks are aligned to the clock and never drift, so a 5 second interval ticks when the clock reaches the seconds 0, 5, 10, 15 etc. The optionalnumberOfTicksparameter stops the rebuilds after that number of ticks.
- New
-
12.8.027 Jul 2026Release notes
Open source →-
New
RowProportionalwidget, which arranges its children horizontally, dividing all the available horizontal space between them, proportionally to their preferred (natural, intrinsic) widths. Children are forced to their calculated widths, so the row never overflows: with extra space the children grow, and with less space they shrink, always keeping their relative proportions. Wrapping a child in anExpandedmultiplies its preferred width by theflex, while aFlexiblealso allows the child to be smaller than its calculated width. If one or more children areSpacers, there is no scaling anymore: the other children get their preferred widths, and the leftover space is divided between the spacers. -
New
FixedWidthwidget, to be used as a direct child ofRowProportional, gives a child an immutable width that never scales and does not participate in the proportional distribution of space. UseFixedWidth(width: 8)with no child for a fixed 8 pixel gap,FixedWidth(width: 50, child: ...)to pin a child at exactly 50 pixels, orFixedWidth(child: ...)with no width to fix a child at its own preferred width. If the fixed widths alone exceed the available space, they shrink proportionally to each other, so the row still never overflows.
-
-
12.7.127 Jul 2026Release notes
Open source →AnimatedBetweennow reports proper intrinsic dimensions, so it can be used inside parents that measure children by intrinsics (IntrinsicWidth,IntrinsicHeight,RowSuper, etc.). At rest it reports its child's intrinsics; mid-transition it reports the current animated box size, so intrinsic-measuring parents animate along. Visual behavior is unchanged.
-
12.7.024 Jul 2026Release notes
Open source →ThousandsSeparatorTextInputFormatternow accepts anallowedIntegerDigitsparameter that limits the integer part to the given number of digits, just likeallowedDecimalslimits the fractional part. Leading zeros don't count toward the limit, since they are stripped anyway.
-
12.6.206 Jun 2026Release notes
Open source →-
New
OtpCodeVerificationFieldwidget for one-time-password / verification flows: a row of digit boxes that auto-submits when the last character is entered, with built-in handling for wrong-code, verification-failure, and expiry states, plus an optional countdown timer. Accepted characters are configurable viacodeType,codeLetterSet,codeLetterCasing, andcustomSet, and almost everything visual can be customized. -
New
Emailclass for email-address handling:isValid()validates an address (with optional top-level-domain and international-character support),sanitize()strips obviously invalid characters, andtryFix()attempts to repair an invalid address into a valid one. The matchingEmailTextInputFormatterusessanitize()to strip invalid characters as the user types. -
New
CapitalizationTextInputFormattercapitalizes text as the user types, with options for uppercase, lowercase, first-letter, or English title case. -
New
NumbersTextInputFormatterallows only numeric input — integer, or decimal with locale-aware, dot, or comma separators. -
New
AllowedCharsTextInputFormatterallows only the characters that match a given regular expression, filtering out everything else. -
New
NoSpacesTextInputFormatterprevents the user from typing any whitespace, removing spaces, tabs, and newlines from the input. -
New
AlwaysAtTheEndTextInputFormatterforces the cursor to always stay at the end of the text being typed. -
New
StringDotLengthLimiterTextInputFormatterlimits text by Dart'sString.length(instead of grapheme clusters), useful when matching server, database, or file-format limits.
-
-
12.6.101 May 2026Nothing published for this version
-
12.6.001 May 2026Nothing published for this version
-
12.5.126 Apr 2026Release notes
Open source →-
Widget
KeyboardDismissis now deprecated.To fix the deprecation warning, replace:
KeyboardDismiss(child: ...)with:
Keyboard( iOsCloseOnTap: true, iOsCloseOnSwipe: true, iOsRemoveFocusOnTap: true, child: ... ) -
The new
Keyboardwidget allows you to show different content depending on whether the system keyboard is open or closed. If also controls the behavior of the system keyboard on both iOS and Android, including auto-dismissing the keyboard when the user taps outside it or swipes down from just above the keyboard edge.Place the
Keyboardwidget near the top of the widget tree, where it has the same size as the screen, for example, inMaterialApp.builder, above anyScaffold. For example:MaterialApp( builder: (BuildContext context, Widget? child) => Keyboard( iOsCloseOnTap: true, iOsCloseOnSwipe: true, iOsRemoveFocusOnTap: true, child: ..., );Here are the constructor parameters:
iOsCloseOnTapcloses the keyboard when the user taps an empty area of the screen, on the iOS.iOsCloseOnSwipecloses the keyboard when the user swipes down from just above the keyboard edge, on the iOS.iOsRemoveFocusOnTapcontrols whether focus is also removed from any focused element when the keyboard is dismissed by a tap, on the iOS.iOsRemoveFocusOnSwipecontrols whether focus is also removed from any focused element when the keyboard is dismissed by a swipe, on the iOS.androidCloseOnTapcloses the keyboard when the user taps an empty area of the screen, on the Android.androidCloseOnSwipecloses the keyboard when the user swipes down from just above the keyboard edge, on the Android.androidRemoveFocusOnTapcontrols whether focus is also removed from any focused element when the keyboard is dismissed by a tap, on the Android.androidRemoveFocusOnSwipecontrols whether focus is also removed from any focused element when the keyboard is dismissed by a swipe, on the Android.
The default is
falsefor all the above parameters.Recommendation
On the iOS, it's common for the keyboard to auto-dismiss when the user taps outside it or swipes down from just above the keyboard edge. Usually, when the keyboard is dismissed by a tap, the focused element also loses focus, but when it's dismissed by a swipe, the focused element retains focus (and may re-open the keyboard if it's tapped).
On the Android, the default is that the keyboard only closes when the user taps the back button or executes the back gesture.
For these reasons, the recommended configuration is:
Keyboard( iOsCloseOnTap: true, iOsCloseOnSwipe: true, iOsRemoveFocusOnTap: true, child: ... ); -
Keyboard.isOpen(context)can be used to check whether the keyboard is currently open or not. Example usage:bool isKeyboardOpen = Keyboard.isOpen(context);. -
Use
Keyboard.open()andKeyboard.close()to programmatically open and close the system keyboard. -
The new
KeyboardSwitchwidget renders different content depending on whether the system keyboard is open or closed. There are two ways to use it:-
The default constructor takes optional
openandclosedwidgets. Theopenwidget is shown when the keyboard is open, and theclosedwidget when it is closed. Both are optional, and a missing slot renders nothing. Example usage:KeyboardSwitch( open: Text('Keyboard is open'), closed: Text('Keyboard is closed'), ) -
The
KeyboardSwitch.builderconstructor takes abuildercallback that receives the currentisOpenstate, so you can build any widget you want based on it. Example usage:KeyboardSwitch.builder( (context, isOpen) => Icon(isOpen ? Icons.keyboard : Icons.keyboard_hide), )
Note
KeyboardSwitchonly works if you add aKeyboardwidget ancestor. An error will be thrown if you try to use it without aKeyboardancestor. -
-
-
12.5.026 Apr 2026Nothing published for this version
-
12.4.217 Apr 2026Release notes
Open source →- Added
AnimatedBetweenwidget, which animates smoothly between two children, cross-fading their content while resizing the enclosing box. The old and new children can differ in both width and height, and their sizes don't need to be known in advance. The convenience constructorAnimatedBetween.showHideanimates a single widget in and out.
- Added
-
12.4.117 Apr 2026Nothing published for this version
-
12.4.017 Apr 2026Nothing published for this version
-
12.3.102 Apr 2026Release notes
Open source →-
Added
ThousandsSeparatorTextInputFormatter, a formatter for your text-field that formats numeric input with thousands separators as the user types, while preserving the caret position. It accepts integers and decimals. -
Added
KeepTallestwidget, which tracks its child's height and never visually shrinks below the tallest height observed so far. Useful for preventing layout jumps when switching between children of different heights (e.g. tab content inside scrollables). Optionally supports animated shrinking back to the child's natural height, with configurable delay, duration, curve, and minimum shrink threshold.
-
-
12.3.030 Mar 2026Nothing published for this version
-
12.2.030 Mar 2026Nothing published for this version
-
12.1.130 Mar 2026Nothing published for this version
-
12.1.030 Mar 2026Nothing published for this version
-
12.0.004 Mar 2026Release notes
Open source →-
Bumped environment:
- sdk: '>=3.9.2 <4.0.0'
- flutter: ">=3.35.6"
-
Fixed
Buttonvisual bug: Whendelayis true and the user taps quickly (before the delay timer fires), the visual press feedback now still shows briefly usingminVisualTapDuration, instead of being skipped entirely.
-
-
11.0.024 Jan 2025Release notes
Open source →- Breaking change: The signature of the builders of
TimeBuilderhave been changed. They all now use named parameters, and also get a newinitialTimeparameter that was not present before. Migration should be straightforward, Refer to the README for more information.
- Breaking change: The signature of the builders of
-
11.0.0-dev.124 Jan 2025 pre-releaseNothing published for this version
-
10.7.023 Jan 2025Release notes
Open source →- The
ScrollShadowwidget adds a shadow at the top and/or bottom, to scrollables likeSingleChildScrollVieworListViewetc., when the content doesn't fit the scrollable's viewport. As the shadow appears only if there is content outside the viewable area, this gives the user an indication if there is more content to be seen or not.
- The
-
10.6.123 Jan 2025Release notes
Open source →-
The
DetectScrollwidget can detect if the content of a Scrollable is larger than the Scrollable itself, which means that the content can be scrolled, and that a scrollbar is likely visible. It can also tell you the probable width of that scrollbar.This is useful for positioning widgets relative to the scrollbar, so that the scrollbar doesn't overlap them. This can be important when the scrollbar is permanently visible, usually on the Web and desktop.
Note that
DetectScrollwill only detect the scrolling of its closest scrollable descendant (a scrollable is aSingleChildScrollView,ListView,GridViewetc.). Usually, you'd wrap the scrollable you care about directly with aDetectScroll. For example:
DetectScroll( child: SingleChildScrollView( child: Column( ... ... );
To get the current scroll state and the scrollbar width, descendants can call:bool canScroll = DetectScroll.of(context).canScroll; double scrollbarWidth = DetectScroll.of(context).scrollbarWidth;
For example, suppose you want to add a help button to the top-right corner of a scrollable, and account for the scrollbar width only if it's visible:bool canScroll = DetectScroll.of(context).canScroll; double scrollbarWidth = DetectScroll.of(context).scrollbarWidth;
return Stack( children: [ child, Positioned( right: canScroll ? scrollbarWidth : 0, top: 0, child: HelpButton(), ), ], );
Another alternative is using the optional `onChange` callback of the `DetectScroll`:DetectScroll( onChange: ({ required bool canScroll, required double scrollbarWidth, }) { // Do something. } child: ... ),
-
-
10.6.020 Jan 2025Nothing published for this version
-
10.5.017 Jan 2025Release notes
Open source →- The
SideBySidewidget now has amainAxisSizeproperty the determines whether it will occupy the full available width (MainAxisSize.max) or only as much as it needs (MainAxisSize.min).
- The
-
10.4.410 Jan 2025Nothing published for this version
-
10.4.310 Jan 2025Nothing published for this version
-
10.4.210 Jan 2025Nothing published for this version
-
10.4.109 Jan 2025Nothing published for this version
-
10.4.009 Jan 2025Nothing published for this version
-
10.3.009 Jan 2025Release notes
Open source →-
CircleButtonnow accepts an optional custom builder function to modify the button's child widget. This can be used to animate the button when the button is tapped, or when the mouse is over it. For example:
CircleButton( icon: Icon(Icons.shopping_cart),
builder: ({ required bool isHover, required bool isPressed, required Widget child, }) => AnimatedScale( scale: isPressed ? 0.85 : 1.0, duration: const Duration(milliseconds: 50), child: child, ), );Try running the [example](https://github.com/marcglasberg/assorted_layout_widgets/blob/master/example/lib/main_button_and_circle_button.dart). -
-
10.2.406 Jan 2025Release notes
Open source →-
SideBySidewidget now allows for any number of children, not just two. Example:
SideBySide( children: [ Text("Hello!", textWidthBasis: TextWidthBasis.longestLine), Text("How are you?", textWidthBasis: TextWidthBasis.longestLine), Text("I'm good, thank you.", textWidthBasis: TextWidthBasis.longestLine), ], gaps: [8.0, 12.0], );
The `SideBySide` widget achieves layouts that are not possible with `Row` or `RowSuper` widgets. Read the documentation for more information. **Deprecated usage:** The `startChild` and `endChild` parameters are deprecated. Use the `children` parameter instead. The `innerDistance` parameter is also deprecated. Use the `gaps` parameter instead. For example, this deprecated code:return SideBySide( startChild: Text("Hello!", textWidthBasis: TextWidthBasis.longestLine), endChild: Text("How are you?", textWidthBasis: TextWidthBasis.longestLine), innerDistance: 8.0, );
Should be replaced with:return SideBySide( children: [ Text("Hello!", textWidthBasis: TextWidthBasis.longestLine), Text("How are you?", textWidthBasis: TextWidthBasis.longestLine), ], gaps: [8.0], );
-
-
10.2.306 Jan 2025Nothing published for this version
-
10.2.206 Jan 2025Nothing published for this version
-
10.2.106 Jan 2025Nothing published for this version
-
10.2.005 Jan 2025Nothing published for this version
-
10.1.202 Jan 2025Release notes
Open source →-
The
Boxwidget can now have adecoration, as well as adecorationPosition. Previously, if aContainerhad a decoration you could not replace it with aBox, but now you can. Note theBoxis a little more flexible than theContainerwhen you define acolorand aBoxDecorationor aShapeDecorationat the same time, as theBoxwill only throw an error if thecoloris defined twice. -
You can use
Box.gap()to create a small gap between widgets:
Column( children: [ Text('A'), const Box.gap(8), // 8.0 pixel gap Text('B'), ]);
-
-
10.1.101 Jan 2025Nothing published for this version
-
10.1.027 Dec 2024Nothing published for this version
-
10.0.405 Nov 2024Release notes
Open source →- Fixed
GestureDetectorordering issue forRowSuperandColumnSuperwhen theinvertparam istrue.
- Fixed
-
10.0.330 Oct 2024Release notes
Open source →-
Removed
KeyboardDismissdependency ondart:ioto make it compatible with platform web. -
Now
CircleButtoncan specifyhoverColor(default is no color), andcursor(the default isSystemMouseCursors.click, but you can passnullto set it asMouseCursor.defer).
-
-
10.0.229 Oct 2024Nothing published for this version
-
10.0.129 Oct 2024Nothing published for this version
-
10.0.029 Oct 2024Nothing published for this version
-
9.1.0-dev.103 Oct 2024 pre-releaseNothing published for this version
-
9.0.220 Jun 2024 -
9.0.124 Jan 2024 -
9.0.017 Nov 2023Nothing published for this version
-
8.0.508 Oct 2023 -
8.0.401 Jun 2023Release notes
Open source →- Removed deprecated
TextOneLineEllipsisWithFadewidget. Please useTextOneLineinstead.
- Removed deprecated
-
8.0.301 Jun 2023Nothing published for this version
-
8.0.201 Jun 2023Nothing published for this version
-
8.0.101 Jun 2023Nothing published for this version
-
8.0.017 Mar 2023Nothing published for this version
-
7.0.117 Mar 2023 -
7.0.030 Aug 2022Release notes
Open source →-
Flutter 3.3.0 (Dart 2.18.0).
-
TextOneLineEllipsisWithFadedeprecated. Please useTextOneLineinstead.
-
-
6.1.120 Jun 2022 -
6.1.020 Jun 2022Nothing published for this version