Flutter:FutureBuilder 一直闪烁

Flutter: FutureBuilder keeps flashing

我在调用 setState() 时遇到问题。

这是问题的屏幕录像:https://cln.sh/ndL24t

如您所见,单击小部件会导致图片从加载到图片闪烁。

问题是因为我有两个期货,因此是未来的建设者。第一个 future returns 将要显示的信息。第二个未来 returns 基于仪表板上显示的条目的 id 的图像。我有第一个未来的建设者得到文本未来。我将未来设置在 initState() 以避免重复调用。然后我在 initState() 中设置了另一个 Future 变量,如下 journalFuture.then(...)。我还有一个 AnimatedContainer(),当用户点击或 up/cancels 通过更改值并调用 setState() 时,它会进行动画处理。我认为这是问题的原因,但我不知道如何解决它。

这是我的代码:

  const JournalSummary({Key? key}) : super(key: key);

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

class _JournalSummaryState extends State<JournalSummary> {
  final GlobalKey lottieKey = GlobalKey(debugLabel: 'Lottie Key');

  late Future<List<JournalEntryData>> journalFuture;
  Future? picturesFuture;

  late Color _shadowColor;
  double _blurRadius = 15;

  void _animateDown() {
    setState(() {
      _shadowColor = Theme.of(context).shadowColor.withOpacity(0.40);
      _blurRadius = 25;
    });
  }

  void _animateUp() {
    setState(() {
      _shadowColor = Theme.of(context).shadowColor.withOpacity(0.19);
      _blurRadius = 15;
    });
  }

  @override
  void initState() {
    super.initState();
    journalFuture = DatabaseService(uid: AuthService().getUser()!.uid)
        .getJournalEntries(limit: 10);

    journalFuture.then((entries) {
      if (entries.isNotEmpty) {
        entries
            .sort((JournalEntryData firstEntry, JournalEntryData secondEntry) {
          DateTime firstDate = DateTime.parse(firstEntry.date);
          DateTime secondDate = DateTime.parse(secondEntry.date);

          int feelingCmp = secondEntry.feeling.compareTo(firstEntry.feeling);

          if (feelingCmp != 0) return feelingCmp;
          return secondDate.compareTo(firstDate);
        });
      }

      picturesFuture = StorageService(AuthService().getUser()!.uid)
          .getPictures(entries[0].date);
    });
  }

  @override
  void didChangeDependencies() {
    super.didChangeDependencies();
    _shadowColor = Theme.of(context).shadowColor.withOpacity(0.19);
  }

  @override
  Widget build(BuildContext context) {
    return Material(
      color: Colors.transparent,
      child: FutureBuilder(
        future: journalFuture,
        builder: (context, entryFuture) {
          List<JournalEntryData> entries =
              (entryFuture.data as List<JournalEntryData>?) ?? [];

          if (entries.isNotEmpty) {
            entries.sort(
                (JournalEntryData firstEntry, JournalEntryData secondEntry) {
              DateTime firstDate = DateTime.parse(firstEntry.date);
              DateTime secondDate = DateTime.parse(secondEntry.date);

              int feelingCmp =
                  secondEntry.feeling.compareTo(firstEntry.feeling);

              if (feelingCmp != 0) return feelingCmp;
              return secondDate.compareTo(firstDate);
            });
          }

          return GestureDetector(
            onTap: () => AppTheme.homeNavkey.currentState!.pushReplacement(
              PageRouteBuilder(
                transitionDuration: Duration(milliseconds: 320),
                pageBuilder: (BuildContext context, Animation<double> animation,
                    Animation<double> secondaryAnimation) {
                  return Tasks(false);
                },
                transitionsBuilder: (BuildContext context,
                    Animation<double> animation,
                    Animation<double> secondaryAnimation,
                    Widget child) {
                  return Align(
                    child: FadeTransition(
                      opacity: animation,
                      child: child,
                    ),
                  );
                },
              ),
            ),
            onTapDown: (_) => _animateDown(),
            onTapUp: (_) => _animateUp(),
            onTapCancel: () => _animateUp(),
            child: AnimatedContainer(
              duration: const Duration(milliseconds: 200),
              margin: const EdgeInsets.symmetric(vertical: 10, horizontal: 25),
              padding: const EdgeInsets.symmetric(vertical: 15, horizontal: 10),
              clipBehavior: Clip.hardEdge,
              decoration: BoxDecoration(
                color: Theme.of(context).backgroundColor,
                borderRadius: BorderRadius.circular(15),
                boxShadow: [
                  BoxShadow(
                    color: _shadowColor,
                    blurRadius: _blurRadius,
                  ),
                ],
              ),
              child: Padding(
                padding: const EdgeInsets.symmetric(horizontal: 5),
                child: Column(
                  crossAxisAlignment: CrossAxisAlignment.start,
                  children: [
                    Row(
                      mainAxisSize: MainAxisSize.max,
                      mainAxisAlignment: MainAxisAlignment.center,
                      children: [
                        SvgPicture.asset(
                          'assets/adobe/illustrator/icons/svg/journal_selected.svg',
                          width: 35,
                          height: 35,
                        ),
                        SizedBox(width: 8),
                        Text(
                          entryFuture.data == null
                              ? 'Journal'
                              : _formatedDate(entries[0].date),
                          maxLines: 1,
                          overflow: TextOverflow.ellipsis,
                          style: Theme.of(context)
                              .textTheme
                              .subtitle2!
                              .copyWith(color: Theme.of(context).primaryColor),
                        ),
                        Spacer(),
                        (entryFuture.data == null)
                            ? Container()
                            : Lottie.asset(
                                'assets/lottie/faces/${(entries[0].feeling == 1 ? 'sad' : (entries[0].feeling == 2 ? 'meh' : 'happy'))}.json',
                                key: lottieKey,
                                repeat: false,
                                width: 50,
                                height: 50,
                              ),
                      ],
                    ),
                    SizedBox(height: 10),
                    FutureBuilder(
                      key: UniqueKey(),
                      future: picturesFuture,
                      initialData: [],
                      builder: (context, picFuture) {
                        return (picFuture.connectionState ==
                                    ConnectionState.waiting ||
                                picturesFuture == null)
                            ? Center(child: CircularProgressIndicator())
                            : SizedBox(
                                width:
                                    MediaQuery.of(context).size.width - 40 - 50,
                                height: 160,
                                child: ListView(
                                  scrollDirection: Axis.horizontal,
                                  clipBehavior: Clip.none,
                                  children: _buildPictures(
                                      (picFuture.data as List<Uint8List>)),
                                ),
                              );
                      },
                    ),
                    SizedBox(height: 10),
                    (entryFuture.data == null)
                        ? Container()
                        : Text(
                            entries[0].entryText,
                            style: Theme.of(context).textTheme.bodyText2,
                            maxLines: 3,
                            overflow: TextOverflow.ellipsis,
                          ),
                  ],
                ),
              ),
            ),
          );
        },
      ),
    );
  }

  List<Widget> _buildPictures(List<Uint8List> pictures) {
    List<Widget> picWidgets = [];
    int index = 0;
    for (var pic in pictures) {
      picWidgets.add(
        Container(
          key: UniqueKey(),
          decoration: BoxDecoration(
            borderRadius: BorderRadius.circular(10),
            boxShadow: [
              BoxShadow(
                blurRadius: 6,
                color: Theme.of(context).shadowColor.withOpacity(0.52),
                offset: Offset(0, 3),
              )
            ],
          ),
          clipBehavior: Clip.hardEdge,
          margin: index == 0
              ? EdgeInsets.only(right: 10)
              : EdgeInsets.symmetric(horizontal: 10),
          child: Image.memory(
            pic,
            key: UniqueKey(),
            height: 160,
            fit: BoxFit.cover,
          ),
        ),
      );
      index += 1;
    }
    return picWidgets;
  }

  String _formatedDate(String date) {
    DateTime dateTime = DateTime.parse(date);
    Map<int, String> _monthNumToName = {
      1: 'Jan',
      2: 'Feb',
      3: 'Mar',
      4: 'Apr',
      5: 'May',
      6: 'Jun',
      7: 'Jul',
      8: 'Aug',
      9: 'Sep',
      10: 'Oct',
      11: 'Nov',
      12: 'Dec',
    };

    return '${_monthNumToName[dateTime.month]} ${dateTime.day}, ${dateTime.year}';
  }
}

成功了。正如我的评论中提到的,我在问题发布后 运行 flutter upgrade 因为发布问题后出现了新版本,并且还稍微更改了代码所以我不确定是什么解决了问题.也可能是我停止了 运行 然后 运行 应用程序。