FutureBuilder 方法 'findRenderObject' 被调用为 null

FutureBuilder The method 'findRenderObject' was called on null

我想渲染一个由 FutureBuilder 构建的 RichText 的位置,如下面的代码,我在 initState() 中使用了 WidgetsBinding.instance.addPostFrameCallback 但我得到了一个错误:The method 'findRenderObject' was called on null.,我在没有 FutureBuilder 的情况下尝试了这种方法,效果很好,我不知道如何使用 FutureBuilder

解决这个问题
class 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));
}

可以在呈现后查询文本位置。

例如,您可以将 ListView 移动到单独的小部件。调用 postframe 回调时,文本将已经存在,因此您将获得其位置

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));
  }
}

但是这种方法使代码复杂化并且看起来不可靠。

或者,如果您想滚动到列表视图项目,您可以使用 scrollable_positioned_list package。它提供了更多声明 api:

final ItemScrollController itemScrollController = ItemScrollController();

ScrollablePositionedList.builder(
  itemCount: ...,
  itemBuilder: (context, index) => ...,
  itemScrollController: itemScrollController,
);

itemScrollController.jumpTo(
  index: 100,
  alignment: 0.5,
);