簡體   English   中英

嘗試預加載小部件時避免重建

[英]Avoid rebuilding when trying to preload widgets

我正在嘗試構建一個類似於 tinder 的系統,其中有一堆卡片可供用戶刷卡,並且總是預加載接下來的幾張卡片。

為此,我有一個Stack小部件,它構建了一系列卡片子小部件,並為它們提供要加載的內容的 id:

class PostCardStack extends StatefulWidget {
  const PostCardStack({Key key, this.postIds, this.onCardDismissed})
      : super(key: key);

  final List<String> postIds;
  final Function onCardDismissed;

  @override
  _PostCardStackState createState() => _PostCardStackState();
}

class _PostCardStackState extends State<PostCardStack> {
  ValueNotifier<double> _notifier = ValueNotifier<double>(0.0);

  _buildCardStack() {
    List<Widget> cards = [];
    for (String postId in widget.postIds) {
      int idx = widget.postIds.indexOf(postId);
      if (postId == widget.postIds.first) {
        cards.add(CustomDismissible(
            resizeDuration: null,
            dismissThresholds: {CustomDismissDirection.horizontal: 0.2},
            notifier: _notifier,
            key: Key(postId),
            onDismissed: (direction) {
              _notifier.value = 0.0;
              widget.onCardDismissed(postId);
            },
            child: SlidablePanel(
              panel: AnimatedBuilder(
                  animation: _notifier,
                  child: PostCard(
                    postId: postId,
                  ),
                  builder: (context, _) {
                    return Opacity(
                        opacity: 1 - _notifier.value,
                        child: PostCard(
                          postId: postId,
                        ));
                  }),
            )));
      } else {
        cards.add(AnimatedBuilder(
            animation: _notifier,
            child: PostCard(
              postId: postId,
            ),
            builder: (context, _) {
              return Opacity(
                  opacity: lerpDouble(1 - (0.1 * idx), 1 - ((0.1 * idx) - 0.1),
                      _notifier.value),
                  child: Transform(
                      origin: null,
                      alignment: Alignment.bottomCenter,
                      transform: Matrix4.translationValues(
                          0.0,
                          lerpDouble(
                              -idx * 35, (-idx * 35 + 35), _notifier.value),
                          0.0)
                        ..scale(
                            lerpDouble(1 - (0.1 * idx), 1 - ((0.1 * idx) - 0.1),
                                _notifier.value),
                            lerpDouble(1 - (0.1 * idx), 1 - ((0.1 * idx) - 0.1),
                                _notifier.value),
                            1),
                      child: PostCard(
                        postId: postId,
                      )));
            }));
      }
    }
    return cards.reversed.toList();
  }

  @override
  Widget build(BuildContext context) {
    return Stack(
        alignment: Alignment.bottomCenter, children: _buildCardStack());
  }
}

PostCard小部件中,我使用postId參數來獲取卡片信息並在它准備好時構建它。

class PostCard extends StatefulWidget {
  const PostCard({Key key, this.postId}) : super(key: key);

  final String postId;

  @override
  _PostCardState createState() => _PostCardState();
}

class _PostCardState extends State<PostCard> {
  PostModel post;

  @override
  void initState() {
    super.initState();
    print("${widget.postId} mounted");
    _fetchPost(widget.postId);
  }

  @override
  void dispose() {
    print("${widget.postId} disposed");
    super.dispose();
  }

  _fetchPost(String postId) async {
    PostModel fullPost = await blablaFirestore(postId);

    setState(() {
      post = fullPost;
    });
  }

  @override
  Widget build(BuildContext context) {
    return Container(
      height: 300,
      child: Align(
        alignment: Alignment.topCenter,
        child: Text(post == null ? "Loading..." : post.text),
      ),
    );
  }
}

一切正常,除非堆棧組件中的 id 列表的任何元素發生更改,所有子卡都被重建,因此丟失了之前加載的 state 並且必須再次獲取數據。

如果 id 列表中只有一個元素發生變化,為什么每張卡片都在重建? 我在這里錯過了什么嗎? :)

編輯:在標記為重復的問題中,問題是具有副作用的構建方法。 我不相信這里是這種情況。 就我而言,問題是 PostCards 小部件的 state 沒有保留,即使它們使用完全相同的參數(postId)重建

干杯!

setState被調用時, build function 被再次調用,並且所有PostCard小部件將被重新創建,因為它們是在build function 中創建的。

這就是說,如果PostCard是一個Stateful的小部件,那么 state 不應該被破壞(例如 initState 不會被調用)。 但是您可能會失去對它們的引用,這可能就是您的代碼沒有按預期運行的原因(很難從您的代碼中分辨出來)。

也許您應該將這段代碼稱為有Stateful小部件的小部件並創建一個List<PostCard> postCards變量來存儲您的卡片,這樣您就可以在initState function 中初始化postCards並且在您調用setState時不會重新創建它們,從而保留參考。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM