Флаттер: FutureBuilder продолжает мигать

#flutter #dart #stateful #statefulwidget

Вопрос:

У меня проблема при звонке setState() .

Вот экранная запись проблемы: https://cln.sh/ndL24t.

Как вы можете видеть, нажатие на виджет приводит к тому, что картинка мигает от загрузки к картинке.

Проблема вызвана тем, что у меня есть два будущего и, следовательно, для будущих строителей. Первое будущее возвращает информацию, которая будет отображаться. Второе будущее возвращает изображения на основе идентификатора записи, отображаемой на панели мониторинга. У меня есть первый строитель будущего, который получит текст будущего. Я настроил будущее на initState() то, чтобы избежать повторных звонков. Затем у меня есть еще Future одна переменная, которую я задаю initState() следующим образом journalFuture.then(...) . У меня также есть AnimatedContainer() функция, которая анимируется, когда пользователь нажимает вниз или вверх/отменяет, изменяя значения и вызывая 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}';
  }
}

 

Комментарии:

1. попробуйте это на реальном телефоне… или подключитесь и запустите с редактором.. проблема может быть в производительности эмулятора..

2. Попробуйте удалить uniqueKey в FutureBuilder из Picturefuture

3. Теперь это работает. Я не уверен, что исправило проблему точно так же, как я сделал несколько вещей одновременно. Я бежал flutter upgrade с тех пор, как была выпущена новая версия, с тех пор как я задал этот вопрос. Я также немного изменил код, но, похоже, это не исправило его до обновления, так что, скорее flutter upgrade всего, это так .

Ответ №1:

Это сработало. Как упоминалось в моем комментарии, я побежал flutter upgrade после публикации вопроса, потому что после публикации вопроса вышла новая версия, а также немного изменил код, поэтому я не уверен, что исправило проблему. Это также могло быть связано с тем, что я перестал работать, а затем снова запустил приложение.