首页 > 解决方案 > How to create sticky shop button animation in Flutter?

问题描述

How can I create this sticky buy button animation of Adidas app in Flutter. I have tried to use a scroll controller to listen for the position of user and then use an animated container but it is of no use since I have to define my scroll controller in my initstate while the height of my containers are relative to my device's height. here is the link of video for the animation: https://drive.google.com/file/d/1TzIUBr6abRQI87xAVu4NOPG67aftzceK/view?usp=sharing

this is what the widget tree looks like:

 Scaffold(appbar,FAB,_body),
_body= SingleChildSrollView child:Column[Container(child:Listview)
,Container(child:PageView(children:[GridView])
,Container
,Container(this is where the shop button should be, the one that replaces the FAB)
,GridView,])

标签: flutterdart

解决方案


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),
      ),
    );
  }
}

推荐阅读