FutureBuilder The method 'findRenderObject' was called on null
It is possible to query the text position after it renders.
For example, you can move ListView
to a separate widget. When postframe callback is called, the text will already exist so you'll get its position
class _BookScreenState extends State<BookScreen> {
@override
Widget build(BuildContext context) {
return FutureBuilder(
future: ...,
builder: (ctx, snapshot) =>
snapshot.connectionState == ConnectionState.waiting
? Center(child: CircularProgressIndicator())
: BooksList(data: snapshot.data),
);
}
}
class BooksList extends StatefulWidget {
final BooksListData data;
BooksList({@required this.data});
@override
_BooksListState createState() => _BooksListState();
}
class _BooksListState extends State<BooksList> {
final GlobalKey _itemKey = GlobalKey();
@override
Widget build(BuildContext context) {
return ListView(
children: [
RichText(
key: _itemKey,
text: TextSpan(
children: _getTextSpan(widget.data),
),
),
],
);
}
void initState() {
super.initState();
WidgetsBinding.instance.addPostFrameCallback((_) {
findRichText();
});
}
void findRichText() {
var richText = _itemKey.currentContext.findRenderObject() as RenderParagraph;
print(richText.localToGlobal(Offset.zero));
}
}
However this approach complicates the code and doesn't seem reliable.
Alternatively, if you want scrolling to listview item, you can use scrollable_positioned_list package. It provides more declarative api:
final ItemScrollController itemScrollController = ItemScrollController();
ScrollablePositionedList.builder(
itemCount: ...,
itemBuilder: (context, index) => ...,
itemScrollController: itemScrollController,
);
itemScrollController.jumpTo(
index: 100,
alignment: 0.5,
);
ynsmtkl
Updated on December 20, 2022Comments
-
ynsmtkl over 1 year
I want to render the position of a RichText built by a FutureBuilder as the code below, I used the
WidgetsBinding.instance.addPostFrameCallback
in theinitState()
but I got an error:The method 'findRenderObject' was called on null.
, I tried this approach without FutureBuilder works fine, I do not know how to solve this with FutureBuilderclass BookScreen extends StatefulWidget { int bookId; BookScreen(this.bookId); @override _BookScreenState createState() => _BookScreenState(); } class _BookScreenState extends State<BookScreen> { final GlobalKey _itemKey = GlobalKey(); void initState() { super.initState(); WidgetsBinding.instance.addPostFrameCallback((_) {findRichText();}); } @override Widget build(BuildContext context) { return FutureBuilder( future: Provider.of<Book>(context, listen: false) .getBookDetail(widget.bookId), builder: (ctx, snapshot) => snapshot.connectionState == ConnectionState.waiting ? Center( child: CircularProgressIndicator(), ) : ListView( children: <Widget>[ Padding( padding: const EdgeInsets.all(10.0), child: RichText( key: _itemKey, // Here is the global key text: TextSpan( children: _getTextSpan(snapshot.data), ), ), ), ], ), ); void findRichText() { var richText = _itemKey.currentContext.findRenderObject() as RenderParagraph; print(richText.localToGlobal(Offset.zero)); }
-
Pavel almost 4 years
findRichText
is called "after the frame". At the timeRichText
doesn't exist yet.CircularProgressIndicator
is shown instead because data is still loading -
Pavel almost 4 yearsWhat do you want to achieve using position of text?
-
ynsmtkl almost 4 yearsI have menu and I want to scroll to that position when the menu clicked, please how to implement that to the RichText be before the frame?
-
-
ynsmtkl almost 4 yearsThank you, your answer is correct, but as you say I am also not happy with this approach so for that I have to change it. thanks