更改 ListView 中当前顶部可见项的颜色 - Flutter

Posted

技术标签:

【中文标题】更改 ListView 中当前顶部可见项的颜色 - Flutter【英文标题】:Change the color of current top visible item in ListView - Flutter 【发布时间】:2020-09-09 23:41:03 【问题描述】:

当用户滚动列表时,我希望列表中的顶部可见项目改变颜色。

我得到的最接近的是插件 ScrollablePositionedList: https://pub.dev/packages/scrollable_positioned_list

当我热重载时,列表中的第一项现在会改变颜色或顶部屏幕上的任何一项。但是当我滚动时,它们不会实时进行。

我非常感谢任何帮助。请在下面找到相关代码。提前致谢!

import 'package:flutter/material.dart';
import 'package:provider/provider.dart';
import 'package:scrollviewexperiment/models/place_data.dart';
import 'package:scrollviewexperiment/widgets/place_tile.dart';
import 'package:scrollable_positioned_list/scrollable_positioned_list.dart';

class PlacesList extends StatefulWidget 
  @override
  _PlacesListState createState() => _PlacesListState();


class _PlacesListState extends State<PlacesList> 
  final ItemPositionsListener itemPositionsListener =
      ItemPositionsListener.create();

  ItemScrollController _itemScrollController = ItemScrollController();
  int currentIndex = 0;



  @override
  void initState() 
    super.initState();
    currentVisibleIndex();
  

  @override
  Widget build(BuildContext context) 
    return Consumer<PlaceData>(
      builder: (context, placeData, child) 
        return ScrollablePositionedList.builder(
          itemCount: placeData.placeCount,
          itemPositionsListener: itemPositionsListener,
          itemBuilder: (context, index) 
            final place = placeData.places[index];
            return Card(
              color: index == currentIndex ? Colors.blue : Colors.white,
              elevation: 2.0,
              shape: RoundedRectangleBorder(
                  borderRadius: BorderRadius.circular(10.0)),
              child: PlaceTile(
                placeName: place.name,
                distance: place.distance,
              ),
            );
          ,
        );
      ,
    );
  

  currentVisibleIndex() 
    itemPositionsListener.itemPositions.addListener(() 
      int min;
      if (itemPositionsListener.itemPositions.value.isNotEmpty) 
        min = itemPositionsListener.itemPositions.value
            .where((ItemPosition position) => position.itemTrailingEdge > 0)
            .reduce((ItemPosition min, ItemPosition position) =>
                position.itemTrailingEdge < min.itemTrailingEdge
                    ? position
                    : min)
            .index;
        print('Min Index $min');
        currentIndex = min;
      
    );
  

【问题讨论】:

【参考方案1】:

我想通了!

我在 ScrollablePositionedList.builder 的 itemBuilder 中返回了一个 ValueListenableBuilder

这不是世界上最干净的解决方案,所以如果有人可以对此进行改进,我很想知道。

import 'package:flutter/material.dart';
import 'package:provider/provider.dart';
import 'package:scrollviewexperiment/models/place_data.dart';
import 'package:scrollviewexperiment/widgets/place_tile.dart';
import 'package:scrollable_positioned_list/scrollable_positioned_list.dart';

class PlacesList extends StatefulWidget 
  @override
  _PlacesListState createState() => _PlacesListState();


class _PlacesListState extends State<PlacesList> 
  final ItemPositionsListener itemPositionsListener =
      ItemPositionsListener.create();

  @override
  Widget build(BuildContext context) 
    return Consumer<PlaceData>(
      builder: (context, placeData, child) 
        return ScrollablePositionedList.builder(
          itemCount: placeData.placeCount,
          itemPositionsListener: itemPositionsListener,
          itemBuilder: (context, index) 
            final place = placeData.places[index];
            return ValueListenableBuilder<Iterable<ItemPosition>>(
              valueListenable: itemPositionsListener.itemPositions,
              builder: (context, positions, child) 
                int min;
                if (positions.isNotEmpty) 
                  min = positions
                      .where((ItemPosition position) =>
                          position.itemTrailingEdge > 0)
                      .reduce((ItemPosition min, ItemPosition position) =>
                          position.itemTrailingEdge < min.itemTrailingEdge
                              ? position
                              : min)
                      .index;
                
                return Card(
                  color: index == min ? Colors.blue : Colors.white,
                  elevation: 2.0,
                  shape: RoundedRectangleBorder(
                      borderRadius: BorderRadius.circular(10.0)),
                  child: PlaceTile(
                    placeName: place.name,
                    distance: place.distance,
                  ),
                );
              ,
            );
          ,
        );
      ,
    );
  

【讨论】:

以上是关于更改 ListView 中当前顶部可见项的颜色 - Flutter的主要内容,如果未能解决你的问题,请参考以下文章

Flutter Using ListView.Builder:如何在我选择的所有项目上仅更改一项的背景颜色

在 Android 上更改 ListView 项目的背景颜色

ListView项目文本是不可见的

如何在listview android中仅更改第二个单元格的背景颜色

Listview builder 创建列表项的副本

Android ListView:获取可见项的数据索引