Google Flutter Widgets
repository·master·Indexed 23 days ago
https://github.com/google/flutter.widgetsA collection of specialized Flutter UI components developed by Google teams outside the core framework. Includes packages such as flutter_simple_treeview for tree structures, linked_scroll_controller for synchronized scrolling, scrollable_positioned_list for index-based scrolling, self_storing_input for automatic data persistence, and visibility_detector for tracking widget visibility.
What's inside google-flutter.widgets
- This repository contains source code for various Flutter widgets developed by Google that are separate from the core Flutter team's development. Note that these widgets and their source code are provided primarily as a reference and are not officially endorsed by Google or the Flutter team. Support is provided on a best-effort basis.
Synchronize multiple scrollable widgets with linked_scroll_controller
masterThe
linked_scroll_controllerpackage allows you to synchronize the scrolling of multiple widgets. You can use aLinkedScrollControllerGroupto manage a set of controllers that move in unison.Key Requirement for Dynamic Controllers: If you add controllers to a group dynamically (for example, inside a
ListView.builder), you must provide uniqueKeys to the corresponding scrollable widgets. Failure to do so may cause the scroll offsets to go out of sync.class _LinkedScrollablesState extends State<LinkedScrollables> { LinkedScrollControllerGroup _controllers; ScrollController _letters; ScrollController _numbers; @override void initState() { super.initState(); _controllers = LinkedScrollControllerGroup(); _letters = _controllers.addAndGet(); _numbers = _controllers.addAndGet(); } @override void dispose() { _letters.dispose(); _numbers.dispose(); super.dispose(); } @override Widget build(BuildContext context) { return Row( children: [ Expanded( child: ListView( controller: _letters, children: [...], ), ), Expanded( child: ListView( controller: _numbers, children: [...], ), ), ], ); } }How VisibilityDetector callback timing works
masterCallbacks in
VisibilityDetectorare not fired immediately upon visibility changes. Instead, they are deferred and coalesced.- Throttling: A callback for a specific
VisibilityDetectorwill be invoked at most once perVisibilityDetectorController.updateInterval. - Batching: Callbacks for all
VisibilityDetectorwidgets are fired together synchronously between frames. - Manual Triggering: You can use
VisibilityDetectorController.notifyNow()to force all pending visibility callbacks to fire immediately. This is useful when tearing down the widget tree, such as when switching views or exiting the application.
- Throttling: A callback for a specific
Implement a Saver for self_storing_input
masterTo use self-storing input widgets, you must first implement a
Saver. ASaveris responsible for loading, validating, and saving data items identified by anitemKey.The
itemKeyis a unique identifier for the data piece and can be any format, such as a resource URL string or a complex tuple like<connectionString, table, objectId, column>.Use LinkedScrollControllerGroup to manage synchronized controllers
masterTo synchronize multiple scrollables, follow this pattern:
- Instantiate a
LinkedScrollControllerGroup. - Use the
.addAndGet()method on the group to create and retrieve newScrollControllerinstances. - Assign these controllers to the
controllerproperty of your scrollable widgets (e.g.,ListView,SingleChildScrollView). - Ensure you call
.dispose()on the individual controllers when they are no longer needed to prevent memory leaks.
- Instantiate a
Configure VisibilityDetector for Widget Tests
masterWhen writing widget tests involving
VisibilityDetector, you may encounter issues with deferred callbacks or pending timers. You have three ways to handle this:Option 1: Immediate Reporting (Recommended)
Set the
updateIntervaltoDuration.zero. This makes visibility changes report immediately and prevents the "A Timer is still pending..." assertion during teardown.VisibilityDetectorController.instance.updateInterval = Duration.zero;Option 2: Manual Pumping
If you want to keep a non-zero interval, manually pump the widget tester for the duration of the interval to allow callbacks to fire.
await tester.pump(VisibilityDetectorController.instance.updateInterval);Option 3: Explicit Teardown
To avoid the "A Timer is still pending..." assertion without changing the interval, explicitly destroy the widget tree by pumping a placeholder before the test completes.
await tester.pumpWidget(Placeholder());Install and use flutter_simple_treeview
masterThe
flutter_simple_treeviewpackage provides a widget for visualizing tree structures in Flutter. Each node in the tree can display any arbitrary widget as its content, allowing for highly customizable tree views.TreeView(nodes: [ TreeNode(content: Text("root1")), TreeNode( content: Text("root2"), children: [ TreeNode(content: Text("child21")), TreeNode(content: Text("child22")), TreeNode( content: Text("root23"), children: [ TreeNode(content: Text("child231")), ], ), ], ), ]),Run the flutter_simple_treeview demo app
masterTo see the
flutter_simple_treeviewpackage in action, including how to control nodes and render JSON as a tree, you can run the provided demo application using the Flutter CLI.flutter run -d chromeClose editing overlays on tap
masterTo ensure that editing overlays close when a user taps elsewhere on the screen, follow these steps:
- Define an
OverlayControllerin your screen state:OverlayController _controller = OverlayController(); - Wrap your screen's
Scaffold(or widget body) with aGestureDetectorthat calls_controller.close()on tap. - Pass the
_controllerinstance to each self-storing widget using theoverlayControllerparameter.
// 1. Define the controller in your state OverlayController _controller = OverlayController(); // 2. Wrap the body in a GestureDetector GestureDetector( onTap: () async { _controller.close(); }, child: Scaffold( body: ... ), ); // 3. Pass the controller to the widget SelfStoringText( overlayController: _controller, // ... other parameters )- Define an
Use ScrollablePositionedList to scroll to specific items
masterThe
ScrollablePositionedListis a Flutter list widget that functions similarly to aListView.builderbut provides the ability to scroll or jump to a specific item index.To use it, you must provide controllers and listeners for item scrolling, item positions, scroll offsets, and offset changes.
Key capabilities:
- Scroll to index: Smoothly animate to a specific item using
itemScrollController.scrollTo. - Jump to index: Instantly move to a specific item using
itemScrollController.jumpTo. - Monitor visibility: Track which items are currently visible on screen using
itemPositionsListener.itemPositions.
final ItemScrollController itemScrollController = ItemScrollController(); final ScrollOffsetController scrollOffsetController = ScrollOffsetController(); final ItemPositionsListener itemPositionsListener = ItemPositionsListener.create(); final ScrollOffsetListener scrollOffsetListener = ScrollOffsetListener.create(); ScrollablePositionedList.builder( itemCount: 500, itemBuilder: (context, index) => Text('Item $index'), itemScrollController: itemScrollController, scrollOffsetController: scrollOffsetController, itemPositionsListener: itemPositionsListener, scrollOffsetListener: scrollOffsetListener, );- Scroll to index: Smoothly animate to a specific item using
Use self-storing input widgets
masterOnce a
Saveris defined, you can add self-storing input widgets to your UI. You must parameterize each widget with your definedSaverand a uniqueitemKey.These widgets automatically handle:
- Loading data from the store
- Validating entered data
- Saving data to the store
- Handling failure modes (e.g., poor internet connection or data storage failures)
Run the self_storing_input demo app
masterTo run the demonstration application for the
self_storing_inputpackage in a web browser, use the Flutter CLI with the Chrome device specified.flutter run -d chrome