flutter_post_frame 0.0.3 copy "flutter_post_frame: ^0.0.3" to clipboard
flutter_post_frame: ^0.0.3 copied to clipboard

A lightweight Flutter package that provides utilities to execute callbacks after the first frame is rendered. Perfect for getting widget sizes or performing post-build operations.

flutter_post_frame #

A lightweight Flutter package that provides utilities to execute callbacks after the first frame is rendered. Perfect for getting widget sizes, managing multiple scroll controllers, or performing post-build operations.

Example #

Example Demo

Features #

  • FlutterPostFrameMixin: A mixin for StatefulWidget states that calls onAfterBuildFrame() after the first frame is rendered.
  • PostFrameBuilder: A widget wrapper that provides a callback with the BuildContext and rendered widget's Size after the first frame.
  • PostFrameScrollBuilder: A widget that manages multiple ScrollControllers with post-frame callbacks.
  • FlutterPostFrameScrollMixin: A mixin for managing multiple scroll controllers with post-frame callbacks.
  • PostFrameScrollManager: A utility class for creating and managing multiple named scroll controllers.

Getting started #

Add the package to your pubspec.yaml:

dependencies:
  flutter_post_frame: ^0.0.1

Then run:

flutter pub get

Usage #

Using FlutterPostFrameMixin #

Add the mixin to your State class to execute code after the first frame:

import 'package:flutter_post_frame/flutter_post_frame.dart';

class MyWidgetState extends State<MyWidget> with FlutterPostFrameMixin<MyWidget> {
  @override
  FutureOr<void> onAfterBuildFrame(BuildContext context) {
    // This runs after the first frame is rendered
    print('Widget has been rendered!');
  }

  @override
  Widget build(BuildContext context) {
    return Container();
  }
}

Using PostFrameBuilder #

Wrap your widget with PostFrameBuilder to get the widget's size after rendering:

import 'package:flutter_post_frame/post_frame_builder.dart';

PostFrameBuilder(
  onAfterBuildFrame: (context, size) {
    print('Widget size: $size');
  },
  child: Container(
    width: 200,
    height: 100,
    color: Colors.blue,
  ),
)

initState-like behavior in StatelessWidget #

Use PostFrameBuilder to execute one-time initialization logic in a StatelessWidget, similar to initState in StatefulWidget:

import 'package:flutter_post_frame/post_frame_builder.dart';

class MyStatelessWidget extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return PostFrameBuilder(
      onAfterBuildFrame: (context, size) {
        // This runs once after the first frame - like initState!
        // Perfect for:
        // - Showing a dialog or snackbar
        // - Triggering navigation
        // - Fetching data based on widget size
        // - Starting animations
        print('Widget initialized with size: $size');
      },
      child: YourContentWidget(),
    );
  }
}

This is especially useful when you want to keep your widget stateless but still need to perform post-build operations.

Using PostFrameScrollBuilder (Multiple ScrollControllers) #

Manage multiple scroll controllers with ease:

import 'package:flutter_post_frame/flutter_post_frame.dart';

PostFrameScrollBuilder(
  controllerKeys: ['list1', 'list2', 'list3'],
  initialScrollOffsets: {'list1': 100.0}, // Optional initial offsets
  onAfterBuildFrame: (data) {
    // Access BuildContext, Size, and scroll manager
    print('Widget size: ${data.size}');
    print('Controllers: ${data.scrollManager.keys}');
    
    // Scroll to a position after build
    data.scrollManager.animateTo(
      'list1',
      200,
      duration: Duration(milliseconds: 300),
    );
  },
  onScroll: (key, offset) {
    // Track scroll position changes for any controller
    print('$key scrolled to: $offset');
  },
  builder: (context, scrollManager) {
    return Row(
      children: [
        Expanded(
          child: ListView.builder(
            controller: scrollManager['list1'],
            itemBuilder: (context, index) => Text('Item $index'),
          ),
        ),
        Expanded(
          child: ListView.builder(
            controller: scrollManager['list2'],
            itemBuilder: (context, index) => Text('Item $index'),
          ),
        ),
      ],
    );
  },
)

Using FlutterPostFrameScrollMixin #

For full control in StatefulWidgets:

import 'package:flutter_post_frame/flutter_post_frame.dart';

class MyWidgetState extends State<MyWidget> 
    with FlutterPostFrameScrollMixin<MyWidget> {
  
  @override
  List<String> get scrollControllerKeys => ['mainList', 'sidebar'];
  
  @override
  Map<String, double>? get initialScrollOffsets => {'mainList': 50.0};

  @override
  FutureOr<void> onAfterBuildFrameWithScroll(PostFrameScrollData data) {
    // Access BuildContext, Size, and scroll manager
    print('Widget size: ${data.size}');
    
    // Add scroll listeners
    scrollManager.addScrollListener('mainList', () {
      print('Scroll offset: ${scrollManager.getScrollOffset('mainList')}');
    });
  }

  @override
  Widget build(BuildContext context) {
    return Row(
      children: [
        Expanded(
          child: ListView(
            controller: scrollManager['mainList'],
            children: [...],
          ),
        ),
        SizedBox(
          width: 200,
          child: ListView(
            controller: scrollManager['sidebar'],
            children: [...],
          ),
        ),
      ],
    );
  }
}

PostFrameScrollManager API #

The PostFrameScrollManager class provides these methods:

final manager = PostFrameScrollManager();

// Create controllers
manager.createController('key', initialScrollOffset: 0.0);

// Access controllers
final controller = manager['key'];  // Or manager.getController('key')

// Scroll operations
manager.animateTo('key', 100, duration: Duration(ms: 300));
manager.jumpTo('key', 100);
manager.scrollToTop('key');
manager.scrollToBottom('key');

// Get scroll information
manager.getScrollOffset('key');
manager.getMaxScrollExtent('key');
manager.getMinScrollExtent('key');

// Listeners
manager.addScrollListener('key', callback);
manager.removeScrollListener('key', callback);

// Cleanup
manager.disposeController('key');
manager.dispose();  // Dispose all

Supported Platforms #

Android iOS Linux macOS Web Windows

Additional information #

This package uses WidgetsBinding.instance.endOfFrame to ensure callbacks are executed after the widget tree has been fully rendered. This is particularly useful when you need to:

  • Get the actual rendered size of a widget
  • Perform navigation or show dialogs after the initial build
  • Execute animations or scroll operations that depend on layout completion

Contributing #

Contributions are welcome! Please feel free to submit a Pull Request.

License #

This project is licensed under the MIT License - see the LICENSE file for details.

2
likes
160
points
191
downloads

Publisher

unverified uploader

Weekly Downloads

A lightweight Flutter package that provides utilities to execute callbacks after the first frame is rendered. Perfect for getting widget sizes or performing post-build operations.

Homepage
Repository (GitHub)
View/report issues

Documentation

API reference

License

MIT (license)

Dependencies

flutter

More

Packages that depend on flutter_post_frame