Quantcast
Channel: Active questions tagged listview - Stack Overflow
Viewing all articles
Browse latest Browse all 611

Flutter ListView not updating despite data list has been updated unless I scrolled all the way to the end

$
0
0

I'm trying to implement this posts-filter functions using Provider in Flutter, the posts has title, timestamp, pfp, and number of likes/comments, my problem is let's say if the user sorted to Oldest what happen is that the value of likes/comments sorted correctly but the title/pfp/timestamp are not and remain static in their current position but until I scrolled all the way down and up the ListView updated and the bug fixed by itself, why?

The filter class:

class SearchPostsFilter with SearchProviderService {  final formatTimestamp = FormatDate();  void filterPostsToBest() {    final sortedVents = searchPostsProvider.vents      .toList()      ..sort((a, b) => a.totalLikes.compareTo(b.totalLikes));    searchPostsProvider.setVents(sortedVents);  }  void filterPostsToLatest() {    final sortedVents = searchPostsProvider.vents      .toList()      ..sort((a, b) => formatTimestamp.parseFormattedTimestamp(b.postTimestamp)        .compareTo(formatTimestamp.parseFormattedTimestamp(a.postTimestamp)));    searchPostsProvider.setVents(sortedVents);  }  void filterPostsToOldest() {    final sortedVents = searchPostsProvider.vents      .toList()      ..sort((a, b) => formatTimestamp.parseFormattedTimestamp(a.postTimestamp)        .compareTo(formatTimestamp.parseFormattedTimestamp(b.postTimestamp)));    searchPostsProvider.setVents(sortedVents);  }  void filterToControversial() {    final sortedVents = searchPostsProvider.vents      .where((post) => post.totalComments >= post.totalLikes)      .toList();    searchPostsProvider.setVents(sortedVents);      }}

The provider/data classes where the post info is stored:

class SearchVents {  String title;  String creator;  String postTimestamp;  Uint8List profilePic;  int totalLikes;  int totalComments;  bool isPostLiked;  bool isPostSaved;  SearchVents({    required this.title,    required this.creator,    required this.postTimestamp,    required this.profilePic,    this.totalLikes = 0,    this.totalComments = 0,    this.isPostLiked = false,    this.isPostSaved = false  });}class SearchPostsProvider extends ChangeNotifier {  List<SearchVents> _vents = [];  List<SearchVents> get vents => _vents;  void setVents(List<SearchVents> vents) {    _vents = vents;    notifyListeners();  }}

The posts ListView:

class SearchPostsListView extends StatefulWidget {  const SearchPostsListView({super.key});  @override  State<SearchPostsListView> createState() => _SearchPostsListViewState();}class _SearchPostsListViewState extends State<SearchPostsListView> {  final sortOptionsNotifier = ValueNotifier<String>('Best');  final searchPostsFilter = SearchPostsFilter();  Widget _buildVentPreview(SearchVents ventData) {    return Padding(      padding: const EdgeInsets.only(bottom: 8.5),      child: DefaultVentPreviewer(        title: ventData.title,        bodyText: '',        creator: ventData.creator,        postTimestamp: ventData.postTimestamp,        totalLikes: ventData.totalLikes,        totalComments: ventData.totalComments,        pfpData: ventData.profilePic,        useV2ActionButtons: true,      ),    );  }  void _sortOptionsOnPressed({required String filter}) {    switch (filter) {      case == 'Best':        searchPostsFilter.filterPostsToBest();        break;      case == 'Latest':        searchPostsFilter.filterPostsToLatest();        break;      case == 'Oldest':        searchPostsFilter.filterPostsToOldest();        break;      case == 'Controversial':        searchPostsFilter.filterToControversial();        break;    }    sortOptionsNotifier.value = filter;    Navigator.pop(context);  }  Widget _buildFilterButtons({    required ValueListenable notifier,     required VoidCallback onPressed  }) {    return SizedBox(      height: 35,      child: InkWellEffect(        onPressed: onPressed,        child: Row(          mainAxisAlignment: MainAxisAlignment.center,          children: [            const SizedBox(width: 8),            const Icon(CupertinoIcons.chevron_down, color: ThemeColor.thirdWhite, size: 15),            const SizedBox(width: 8),            ValueListenableBuilder(              valueListenable: notifier,              builder: (_, filterText, __) {                return Text(                  filterText,                  style: GoogleFonts.inter(                    color: ThemeColor.thirdWhite,                    fontWeight: FontWeight.w800,                    fontSize: 13                  )                );              },            ),            const SizedBox(width: 8),          ],        ),      ),    );  }  Widget _buildListView(List<SearchVents> ventDataList) {    return DynamicHeightGridView(      physics: const AlwaysScrollableScrollPhysics(        parent: BouncingScrollPhysics(),      ),      crossAxisCount: 1,      itemCount: ventDataList.length + 1,      builder: (_, index) {        if (index == 0) {          return Column(            crossAxisAlignment: CrossAxisAlignment.start,            children: [              const SizedBox(height: 12),              Row(                children: [                  _buildFilterButtons(                    notifier: sortOptionsNotifier,                    onPressed: () {                      BottomsheetSearchFilter().buildSortOptionsBottomsheet(                        context: context,                         currentFilter: sortOptionsNotifier.value,                        bestOnPressed: () => _sortOptionsOnPressed(filter: 'Best'),                         latestOnPressed: () => _sortOptionsOnPressed(filter: 'Latest'),                        oldestOnPressed: () => _sortOptionsOnPressed(filter: 'Oldest'),                        controversialOnPressed: () => _sortOptionsOnPressed(filter: 'Controversial'),                      );                    }                  ),                ],              ),              const SizedBox(height: 4),            ],          );        }        final reversedVentIndex = ventDataList.length - index;        if (reversedVentIndex >= 0) {          final vents = ventDataList[reversedVentIndex];          return _buildVentPreview(vents);        }        return const SizedBox.shrink();      },    );  }  @override  void dispose() {    sortOptionsNotifier.dispose();    super.dispose();  }  @override  void initState() {    super.initState();    searchPostsFilter.filterPostsToBest();  }  @override  Widget build(BuildContext context) {    return Consumer<SearchPostsProvider>(      builder: (_, ventData, __) {        final ventDataList = ventData.vents;        return _buildListView(ventDataList);      }    );  }}

Now keep in mind even when ListView is not correctly sorted, somehow when I printed the data list it shows exactly how it should be sorted but it does not reflect on the ListView.

  void filterPostsToOldest() {    final sortedVents = searchPostsProvider.vents      .toList()      ..sort((a, b) => formatTimestamp.parseFormattedTimestamp(a.postTimestamp)        .compareTo(formatTimestamp.parseFormattedTimestamp(b.postTimestamp)));    for(var post in sortedVents) {      print('${post.title} / ${post.postTimestamp}');    }    searchPostsProvider.setVents(sortedVents);  }

So I tried to use KeyedSubtree on the ListView as suggested by ChatGPT but it does not work and nothing changes

return KeyedSubtree(        key: ValueKey('${vents.title}/${vents.creator}'),              child: _buildVentPreview(vents),       );

TLDR; ListView doesn't correctly match with list data.


Viewing all articles
Browse latest Browse all 611

Trending Articles