matteoh
matteoh

Reputation: 3630

Flutter "Build scheduled during frame" error while scrolling a short list and closing the keyboard at the same time

In my Flutter app, I use an AnimatedList, with a few items in it, and a TextFormField on top of it.

One important thing about the list: there is just enough items so the list can scroll when the keyboard is open, but not enough to scroll when the keyboard is closed.

Also, when the user touches the list (touch up), I ask the keyboard to close.

But in some quite-hard-to-reproduce cases, I get the following error:

======== Exception caught by foundation library ====================================================
The following assertion was thrown while dispatching notifications for _StretchController:
Build scheduled during frame.

While the widget tree was being built, laid out, and painted, a new frame was scheduled to rebuild the widget tree.

This might be because setState() was called from a layout or paint callback. If a change is needed to the widget tree, it should be applied as the tree is being built. Scheduling a change for the subsequent frame instead results in an interface that lags behind by one frame. If this was done to make your build dependent on a size measured at layout time, consider using a LayoutBuilder, CustomSingleChildLayout, or CustomMultiChildLayout. If, on the other hand, the one frame delay is the desired effect, for example because this is an animation, consider scheduling the frame in a post-frame callback using SchedulerBinding.addPostFrameCallback or using an AnimationController to trigger the animation.

When the exception was thrown, this was the stack: 
#0      WidgetsBinding._handleBuildScheduled.<anonymous closure> (package:flutter/src/widgets/binding.dart:849:9)
#1      WidgetsBinding._handleBuildScheduled (package:flutter/src/widgets/binding.dart:872:6)
#2      BuildOwner.scheduleBuildFor (package:flutter/src/widgets/framework.dart:2721:24)
#3      Element.markNeedsBuild (package:flutter/src/widgets/framework.dart:5050:12)
#4      State.setState (package:flutter/src/widgets/framework.dart:1223:15)
#5      _AnimatedState._handleChange (package:flutter/src/widgets/transitions.dart:129:5)
#6      ChangeNotifier.notifyListeners (package:flutter/src/foundation/change_notifier.dart:433:24)
#7      AnimationLocalListenersMixin.notifyListeners (package:flutter/src/animation/listener_helpers.dart:161:19)

It happens when I touch up the screen, then touch it back very quickly, before the keyboard has finished to close. And not every time.

Here is the code of my screen:

class _MyHomePageState extends State<MyHomePage> {

  static const _durationMin = Duration.zero;
  final List<String> _items = List.generate(7, (index) => "Item at $index");
  final GlobalKey<AnimatedListState> _listKey = GlobalKey();
  late ScrollController _scrollController;
  
  @override
  void initState() {
    super.initState();
    _scrollController = ScrollController(initialScrollOffset: 0);
  }

  @override
  void dispose() {
    _scrollController.dispose();
    super.dispose();
  }

  Widget _buildItemWidget(String text) {
    return ListTile(
      title: Text(text),
      trailing: IconButton(
        icon: const Icon(Icons.remove),
        onPressed: () {},
      ),
    );
  }
  
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        backgroundColor: Theme.of(context).colorScheme.inversePrimary,
        title: Text(widget.title),
      ),
      body: SafeArea(
        child: Column(
          children: [
            TextFormField(),
            Expanded(
              child: Listener(
                onPointerUp: (_) async {
                  FocusManager.instance.primaryFocus?.unfocus();
                },
                child: AnimatedList(
                  key: _listKey,
                  padding: EdgeInsets.zero,
                  controller: _scrollController,
                  initialItemCount: _items.length,
                  itemBuilder: (context, index, animation)
                  {
                    print("index : $index");
                    return _buildItemWidget(_items[index]);
                  },
                ),
              ),
            ),
            Container(height: 100, color: Colors.red),
          ],
        ),
      ),
    );
  }
  
}

Here is what I tried so far:

So how can I prevent that error from happening?

Thanks for your help.

Upvotes: 0

Views: 560

Answers (1)

Daniel Raj D
Daniel Raj D

Reputation: 1

Try this...

  1. Wrap your column in SingleChildScrollView.

  2. Remove this listener

    Listener(onPointerUp: (_) async { FocusManager.instance.primaryFocus?.unfocus(); },

  3. Use ListView.builder instead of AnimatedList (if still not solved, try this property keyboardDismissBehavior )

If you have better solution than this. Please post here.

Upvotes: 0

Related Questions