Home > front end >  Flutter: change color for first item of the list in the top when stop scrolling in listview
Flutter: change color for first item of the list in the top when stop scrolling in listview

Time:01-25

I have the example code below.

class ExampleScroll extends StatefulWidget {
  const ExampleScroll({Key? key}) : super(key: key);

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

class _ExampleScrollState extends State<ExampleScroll> {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: Scaffold(
        body: ListView.builder(
          itemCount: 20,
          itemBuilder: (context, index) {
            return Card(
              child: Container(
                height: 100,
                color: //TODO: change the color only first item of the list when stoping the scroll
                alignment: Alignment.center,
                child: Text(
                  index.toString(),
                  style:
                  const TextStyle(fontSize: 36.0, fontWeight: FontWeight.bold),
                ),
              ),
            );
          },
        ),
      ),
    );
  }
}

Screenshot: enter image description here enter image description here enter image description here

If see the above screenshot, I stop the scrolling 3x times.

  • First, when the initial (open this screen), the first item of the list in the top is index 0
  • Second, when I stop and the first item of the list in the top is index 13
  • Third, when I stop and the first item of the list in the top is index 17.

So when I scroll the list and stop, first item of the list in the top should be change to green, and the others is white.

For above screenshot (example) I stop 3x times and the first item of the list in the top is in the index 0, 13, 17, so it's change to green.

CodePudding user response:

1. Using ScrollController

class ExampleScroll extends StatefulWidget {
  const ExampleScroll({Key? key}) : super(key: key);

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

class _ExampleScrollState extends State<ExampleScroll> {
  late ScrollController _scrollController;

  final int _itemCount = 20;

  int _cardPosition = 0;

  void _scrollListenerWithItemCount() {
    int itemCount = _itemCount;
    double scrollOffset = _scrollController.position.pixels;
    double viewportHeight = _scrollController.position.viewportDimension;
    double scrollRange = _scrollController.position.maxScrollExtent -
        _scrollController.position.minScrollExtent;
    int firstVisibleItemIndex =
        (scrollOffset / (scrollRange   viewportHeight) * itemCount).floor();

    if (_scrollController.position.atEdge) {
      bool isTop = _scrollController.position.pixels == 0;
      if (isTop) {
        _cardPosition = 0;
      } else {
        _cardPosition = firstVisibleItemIndex   1;
      }
    } else {
      _cardPosition = firstVisibleItemIndex   1;
    }
    setState(() {});
  }

  @override
  void initState() {
    super.initState();
    _scrollController = ScrollController();
    _scrollController.addListener(_scrollListenerWithItemCount);
  }

  @override
  void dispose() {
    super.dispose();
    _scrollController.removeListener(_scrollListenerWithItemCount);
  }

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: Scaffold(
        body: ListView.builder(
          controller: _scrollController,
          itemCount: _itemCount,
          itemBuilder: (context, index) {
            return Card(
              child: Container(
                height: 100,
                color: _cardPosition == index ? Colors.green : Colors.white,
                alignment: Alignment.center,
                child: Text(
                  index.toString(),
                  style: const TextStyle(
                      fontSize: 36.0, fontWeight: FontWeight.bold),
                ),
              ),
            );
          },
        ),
      ),
    );
  }
}

References:

  1. https://github.com/flutter/flutter/issues/19941#issuecomment-522587489
  2. https://stackoverflow.com/a/54539182/8291686

2. Using Area

package: https://pub.dev/packages/inview_notifier_list

CodePudding user response:

I'm not sure if I understand what you mean exactly. but try this out:

class ExampleScroll extends StatefulWidget {
  const ExampleScroll({Key? key}) : super(key: key);

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

class _ExampleScrollState extends State<ExampleScroll> {
  Timer? timer;
  ScrollController controller = ScrollController();

  @override
  void initState() {
    controller.addListener(() {
      if (timer != null) {
        timer!.cancel();
        timer = Timer(Duration(milliseconds: 300), () {
          setState(() {
            timer = null;
          });
        });
      } else {
        timer = Timer(Duration(milliseconds: 300), () {
          setState(() {
            timer = null;
          });
        });
      }
      setState(() {});
    });
    super.initState();
  }

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: Scaffold(
        body: ListView.builder(
          itemCount: 20,
          controller: controller,
          itemBuilder: (context, index) {
            return Card(
              child: Container(
                height: 100,
                color: timer == null
                    ? Colors.black
                    : Colors
                        .green, // I want change this color only for first item
                alignment: Alignment.center,
                child: Text(
                  index.toString(),
                  style: const TextStyle(
                      fontSize: 36.0, fontWeight: FontWeight.bold),
                ),
              ),
            );
          },
        ),
      ),
    );
  }
}

in this code. all tiles change color. for changing only top tile. I recommend using VisibilityDetector

  •  Tags:  
  • Related