Reputation: 3630
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:
FocusManager.instance.primaryFocus?.unfocus();
in a WidgetsBinding.instance.addPostFrameCallback(...)
: I still get the errorFocusManager.instance.primaryFocus?.unfocus();
: it seems to work but it doesn't look like a clean solutionSo how can I prevent that error from happening?
Thanks for your help.
Upvotes: 0
Views: 560
Reputation: 1
Try this...
Wrap your column in SingleChildScrollView.
Remove this listener
Listener(onPointerUp: (_) async { FocusManager.instance.primaryFocus?.unfocus(); },
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