how do you change _Visibility of FloatingActionButton for each ListView item individually?

Viewed 21

I have a ListView.builder which builds a list of dummyText and for each list item i added a _hideButtonController listener. But i am not able to hide each list item individualy. Each time i scroll a list item, all the indicators of other items dissapear as well. How can i make sure that i can hide only the list item that is swiped? I don't want to change anything in the generateList() method.

enter image description here

This is all the code:

import 'dart:convert';
import 'package:flutter/material.dart';
import 'package:flutter/rendering.dart';
import 'package:flutter/services.dart';

void main() async {
  WidgetsFlutterBinding.ensureInitialized();
  runApp(MyApp());
}

class MyApp extends StatelessWidget {
  final ThemeData? themeData;
  const MyApp({Key? key, this.themeData}) : super(key: key);

  @override
  Widget build(BuildContext context) {
    return const MaterialApp(
      title: 'Flutter Demo',
      home: AppView2(),
    );
  }
}

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

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

class _AppViewState extends State<AppView2> {
  late ScrollController _hideButtonController;
  List<String> listData = [];
  var _isVisible;
  String dummyText =
      "Lorem Ipsum is simply dummy text of the printing and typesetting industry. Lorem Ipsum has been the industry's standard dummy text ever since the 1500s, when an unknown printer took a galley of type and scrambled it to make a type specimen book.";

  Future generateList() async {
    listData = [dummyText, dummyText, dummyText, dummyText, dummyText, dummyText, dummyText, dummyText, dummyText, dummyText, dummyText, dummyText, dummyText, dummyText, dummyText, dummyText, dummyText, dummyText, dummyText, dummyText, dummyText, dummyText, dummyText, dummyText, dummyText, dummyText, dummyText, dummyText, dummyText, dummyText, dummyText, dummyText, dummyText, dummyText, dummyText, dummyText, dummyText, dummyText, dummyText, dummyText, dummyText, dummyText, dummyText, dummyText, dummyText, dummyText, dummyText, dummyText, dummyText, dummyText, dummyText, dummyText, dummyText, dummyText, dummyText, dummyText, dummyText, dummyText, dummyText];
    return listData;
  }

  @override
  void initState() {
    generateList();
    _isVisible = true;

    super.initState();
  }

  @override
  Widget build(BuildContext context) {
    return SafeArea(
        child: Scaffold(
            appBar: AppBar(
              title: Text('DataTable'),
            ),
            body: FutureBuilder(
              future: generateList(),
              builder: (context, AsyncSnapshot snapShot) {
                if (snapShot.hasData) {
                  return ListView.builder(
                      shrinkWrap: true,
                      scrollDirection: Axis.vertical,
                      itemCount: snapShot.data.length,
                      itemBuilder: (BuildContext context, int index) {
                        ScrollController _hideButtonController =
                            ScrollController();
                        _hideButtonController.addListener(() {
                          if (_hideButtonController.positions.any((pos) =>
                              pos.userScrollDirection ==
                              ScrollDirection.reverse)) {
                            print(_hideButtonController.positions.first);

                            if (_isVisible == true) {
                              setState(() {
                                _isVisible = false;
                              });
                            } else if (_isVisible == false) {
                              Future.delayed(const Duration(milliseconds: 1000),
                                  () {
                                setState(() {
                                  _isVisible = true;
                                });
                              });
                            }
                          } else {
                            if (_hideButtonController.positions.any((pos) =>
                                pos.userScrollDirection ==
                                ScrollDirection.forward)) {
                              if (_isVisible == true) {
                                setState(() {
                                  _isVisible = false;
                                });
                              } else if (_isVisible == false) {
                                Future.delayed(
                                    const Duration(milliseconds: 1000), () {
                                  setState(() {
                                    _isVisible = true;
                                  });
                                });
                              }
                            }
                          }
                        });
                        return SizedBox(
                          height: 250,
                          child: Stack(
                            children: [
                              CustomScrollView(
                                controller: _hideButtonController,
                                scrollDirection: Axis.horizontal,
                                shrinkWrap: true,
                                slivers: <Widget>[
                                  SliverPadding(
                                    padding: const EdgeInsets.all(20.0),
                                    sliver: SliverList(
                                      delegate: SliverChildListDelegate(
                                        <Widget>[
                                          Center(
                                            child: Text(snapShot.data[index]
                                                .toString()),
                                          )
                                        ],
                                      ),
                                    ),
                                  ),
                                ],
                              ),
                              Visibility(
                                visible: _isVisible,
                                child: Align(
                                  alignment: Alignment.centerRight,
                                  child: FloatingActionButton(
                                      child:
                                          const Icon(Icons.arrow_forward_ios),
                                      onPressed: () {}),
                                ),
                              )
                            ],
                          ),
                        );
                      });
                } else {
                  return CircularProgressIndicator();
                }
              },
            )));
  }
}

class ListModel {
  String title;
  bool isVisible;
  ListModel(this.title, this.isVisible);
}

1 Answers

I mean the best way to handle this type of case is creating a custom widget and let that widget handle each widget's visibility flag. So, create a widget named TextViewer and this widget should be stateful.

An example widget: In your item builder:

itemBuilder: (context, index) => {
    return TextView(text: snapshot.data[index]);
}

and let your TextView widget handle the state of it's visibility

//your imports here:
class TextViewer extends StatefulWidget {
  var text;
  const TextViewer({
    Key? key,
    required this.text,
  }) : super(key: key);

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

class _TextViewerState extends State<TextViewer> {
  late ScrollController _hideButtonController;
  var _isVisible;

  @override
  void initState() {
    _isVisible = true;

    super.initState();
  }

  @override
  Widget build(BuildContext context) {
    ScrollController _hideButtonController = ScrollController();
    _hideButtonController.addListener(() {
      if (_hideButtonController.positions
          .any((pos) => pos.userScrollDirection == ScrollDirection.reverse)) {
        print(_hideButtonController.positions.first);

        if (_isVisible == true) {
          setState(() {
            _isVisible = false;
          });
        } else if (_isVisible == false) {
          Future.delayed(const Duration(milliseconds: 1000), () {
            setState(() {
              _isVisible = true;
            });
          });
        }
      } else {
        if (_hideButtonController.positions
            .any((pos) => pos.userScrollDirection == ScrollDirection.forward)) {
          if (_isVisible == true) {
            setState(() {
              _isVisible = false;
            });
          } else if (_isVisible == false) {
            Future.delayed(const Duration(milliseconds: 1000), () {
              setState(() {
                _isVisible = true;
              });
            });
          }
        }
      }
    });
    return SizedBox(
      height: 250,
      child: Stack(
        children: [
          CustomScrollView(
            controller: _hideButtonController,
            scrollDirection: Axis.horizontal,
            shrinkWrap: true,
            slivers: <Widget>[
              SliverPadding(
                padding: const EdgeInsets.all(20.0),
                sliver: SliverList(
                  delegate: SliverChildListDelegate(
                    <Widget>[
                      Center(
                        child: Text(widget.text),
                      )
                    ],
                  ),
                ),
              ),
            ],
          ),
          Visibility(
            visible: _isVisible,
            child: Align(
              alignment: Alignment.centerRight,
              child: FloatingActionButton(
                  child: const Icon(Icons.arrow_forward_ios), onPressed: () {}),
            ),
          )
        ],
      ),
    );
  }
}

Please ignore any copying mistakes. Hope you understand it's concept. :)

Related