Google Flutter Widgets

repository·master·Indexed 23 days ago

https://github.com/google/flutter.widgets

A 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.

Tokens
6.4K
Snippets
11
Records
35
Agent score
79%

What's inside google-flutter.widgets

  1. Overview of Flutter widgets repository

    master
    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.
  2. Synchronize multiple scrollable widgets with linked_scroll_controller

    master

    The linked_scroll_controller package allows you to synchronize the scrolling of multiple widgets. You can use a LinkedScrollControllerGroup to 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 unique Keys 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: [...],
              ),
            ),
          ],
        );
      }
    }
  3. How VisibilityDetector callback timing works

    master

    Callbacks in VisibilityDetector are not fired immediately upon visibility changes. Instead, they are deferred and coalesced.

    • Throttling: A callback for a specific VisibilityDetector will be invoked at most once per VisibilityDetectorController.updateInterval.
    • Batching: Callbacks for all VisibilityDetector widgets 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.
  4. Implement a Saver for self_storing_input

    master

    To use self-storing input widgets, you must first implement a Saver. A Saver is responsible for loading, validating, and saving data items identified by an itemKey.

    The itemKey is 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>.

  5. Use LinkedScrollControllerGroup to manage synchronized controllers

    master

    To synchronize multiple scrollables, follow this pattern:

    1. Instantiate a LinkedScrollControllerGroup.
    2. Use the .addAndGet() method on the group to create and retrieve new ScrollController instances.
    3. Assign these controllers to the controller property of your scrollable widgets (e.g., ListView, SingleChildScrollView).
    4. Ensure you call .dispose() on the individual controllers when they are no longer needed to prevent memory leaks.
  6. Configure VisibilityDetector for Widget Tests

    master

    When writing widget tests involving VisibilityDetector, you may encounter issues with deferred callbacks or pending timers. You have three ways to handle this:

    Set the updateInterval to Duration.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());
  7. Install and use flutter_simple_treeview

    master

    The flutter_simple_treeview package 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")),
            ],
          ),
        ],
      ),
    ]),
  8. Close editing overlays on tap

    master

    To ensure that editing overlays close when a user taps elsewhere on the screen, follow these steps:

    1. Define an OverlayController in your screen state:
      OverlayController _controller = OverlayController();
    2. Wrap your screen's Scaffold (or widget body) with a GestureDetector that calls _controller.close() on tap.
    3. Pass the _controller instance to each self-storing widget using the overlayController parameter.
    // 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
    )
  9. Use ScrollablePositionedList to scroll to specific items

    master

    The ScrollablePositionedList is a Flutter list widget that functions similarly to a ListView.builder but 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,
    );
  10. Use self-storing input widgets

    master

    Once a Saver is defined, you can add self-storing input widgets to your UI. You must parameterize each widget with your defined Saver and a unique itemKey.

    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)