How to create sticky shop button animation in Flutter?

Output:

enter image description here

void main() => runApp(MaterialApp(home: Scaffold(body: HomePage(), appBar: AppBar())));

class HomePage extends StatefulWidget {
  @override
  _HomePageState createState() => _HomePageState();
}

class _HomePageState extends State<HomePage> with WidgetsBindingObserver {
  ScrollController _controller = ScrollController();
  double _boxHeight = 200, _screenHeight;
  int _itemIndex = 5;
  bool _itemVisibility = true;

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

    double offsetEnd;
    WidgetsBinding.instance.addPostFrameCallback((_) {
      RenderBox box = context.findRenderObject();
      _screenHeight = box.globalToLocal(Offset(0, MediaQuery.of(context).size.height)).dy;
      offsetEnd = ((_itemIndex + 1) - (_screenHeight / _boxHeight)) * _boxHeight;
    });

    _controller.addListener(() {
      if (_controller.position.pixels >= offsetEnd) {
        if (_itemVisibility) setState(() => _itemVisibility = false);
      } else {
        if (!_itemVisibility) setState(() => _itemVisibility = true);
      }
    });
  }

  @override
  Widget build(BuildContext context) {
    return Stack(
      children: <Widget>[
        ListView.builder(
          controller: _controller,
          itemCount: 8,
          itemBuilder: (context, index) {
            return _buildBox(
              index: index,
              color: index == _itemIndex ? Colors.cyan : Colors.blue[((index + 1) * 100) % 900],
            );
          },
        ),
        Positioned(
          bottom: 0,
          right: 0,
          left: 0,
          child: Visibility(
            visible: _itemVisibility,
            child: _buildBox(index: _itemIndex, color: Colors.cyan),
          ),
        ),
      ],
    );
  }

  Widget _buildBox({int index, Color color}) {
    return Container(
      height: _boxHeight,
      color: color,
      alignment: Alignment.center,
      child: Text(
        "${index}",
        style: TextStyle(fontSize: 52, fontWeight: FontWeight.bold),
      ),
    );
  }
}

Another answer (variable height boxes)

enter image description here

void main() => runApp(MaterialApp(home: Scaffold(body: HomePage(), appBar: AppBar())));

class HomePage extends StatefulWidget {
  @override
  _HomePageState createState() => _HomePageState();
}

class _HomePageState extends State<HomePage> with WidgetsBindingObserver {
  ScrollController _controller = ScrollController();
  double _screenHeight, _hRatings = 350, _hSize = 120, _hWidth = 130, _hComfort = 140, _hQuality = 150, _hBuy = 130, _hQuestions = 400;
  bool _itemVisibility = true;

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

    double offsetEnd;
    WidgetsBinding.instance.addPostFrameCallback((_) {
      RenderBox box = context.findRenderObject();
      _screenHeight = box.globalToLocal(Offset(0, MediaQuery.of(context).size.height)).dy;
      offsetEnd = (_hRatings + _hSize + _hWidth + _hComfort + _hQuality + _hBuy) - _screenHeight;
    });

    _controller.addListener(() {
      if (_controller.position.pixels >= offsetEnd) {
        if (_itemVisibility) setState(() => _itemVisibility = false);
      } else {
        if (!_itemVisibility) setState(() => _itemVisibility = true);
      }
    });
  }

  @override
  Widget build(BuildContext context) {
    return Stack(
      children: <Widget>[
        ListView(
          controller: _controller,
          children: <Widget>[
            _buildBox(_hRatings, "Ratings box", Colors.blue[200]),
            _buildBox(_hSize, "Size box", Colors.blue[300]),
            _buildBox(_hWidth, "Width box", Colors.blue[400]),
            _buildBox(_hComfort, "Comfort box", Colors.blue[500]),
            _buildBox(_hQuality, "Quality box", Colors.blue[600]),
            _buildBox(_hBuy, "Buy box", Colors.orange[700]),
            _buildBox(_hQuestions, "Questions part", Colors.blue[800]),
          ],
        ),
        Positioned(
          bottom: 0,
          right: 0,
          left: 0,
          child: Visibility(
            visible: _itemVisibility,
            child: _buildBox(_hBuy, "Buy box", Colors.orange[700]),
          ),
        ),
      ],
    );
  }

  Widget _buildBox(double height, String text, Color color) {
    return Container(
      height: height,
      color: color,
      alignment: Alignment.center,
      child: Text(
        text,
        style: TextStyle(
          fontSize: 32,
          color: Colors.black,
          fontWeight: FontWeight.bold,
        ),
      ),
    );
  }
}

Tags:

Dart

Flutter