Search code examples
flutterflutter-layoutflutter-animationflutter-listviewflutter-pageview

Flutter horizontal Listview/Pageview with selected element animated to full width


so basically I just want to have a horizontal snapping ListView or PageView with items inside, where the currently selected Item will take the whole available full width. This is my base code so far:

    import 'package:flutter/material.dart';

void main() => runApp(MyApp());

class MyApp extends StatefulWidget {
  @override
  _MyAppState createState() => _MyAppState();
}

// Initialize DATA MODEL list with some random values.
List<DataModel> dataList = ['Andrew', 'Test', 'Data', 'Random']
    .map<DataModel>((s) => DataModel(s))
    .toList();

double containerWidth;

class _MyAppState extends State<MyApp> {
  @override
  Widget build(BuildContext context) {
    //var fWidth = MediaQuery.of(context).size.height * 1;

    return MaterialApp(
        title: 'Adjustable height card.',
        home: Scaffold(
          body: ListView.builder(
            controller: PageController(viewportFraction: 0.8),
            scrollDirection: Axis.horizontal,
            itemCount: dataList.length,
            itemBuilder: (context, index) {
              DataModel item = dataList.elementAt(index);

              // Check if the item is expanded or not and set size accordingly
              containerWidth = item.expanded
                  ? MediaQuery.of(context).size.width * 1
                  : MediaQuery.of(context).size.width * 0.30;

              return GestureDetector(
                onDoubleTap: () {
                  setState(() {
                    item.expanded = !item.expanded;
                  });
                },
                child: AnimatedContainer(
                  curve: Curves.easeOut,
                  duration: Duration(milliseconds: 400),
                  color: Colors.red,
                  width: containerWidth,
                  margin: EdgeInsets.all(8),
                  child: Center(
                    child: Text(
                      dataList.elementAt(index).title,
                      style: TextStyle(
                        color: Colors.white,
                      ),
                    ),
                  ),
                ),
              );
            },
          ),
        ));
  }
}

class DataModel {
  String title;
  bool expanded;

  DataModel(this.title) {
    expanded = false;
  }
}

As you can see for now I can give the selected element full width, but I need to have some kind of page snapping, because at the moment im not able to skip the big or small containers in a good way. Now If I change the whole thing to a PageView, I dont have control anymore about the width of AnimatedContainer. Please help.


Solution

  •     import 'package:flutter/material.dart';
    
    void main() {
      runApp(MaterialApp(
        home: MyApp(),
      ));
    }
    class MyApp extends StatefulWidget {
      @override
      _MyAppState createState() => _MyAppState();
    }
    
    // Initialize DATA MODEL list with some random values.
    List<DataModel> dataList = ['Andrew', 'Test', 'Data', 'Random']
        .map<DataModel>((s) => DataModel(s))
        .toList();
    
    double containerWidth;
    
    class _MyAppState extends State<MyApp> {
      @override
      Widget build(BuildContext context) {
    
        return MaterialApp(
            title: 'Adjustable height card.',
            home: Scaffold(
              body: ListView(children: getViewList(),controller: PageController(viewportFraction: 0.8),
                scrollDirection: Axis.horizontal,)
            ));
      }
      List<Widget> getViewList()
      {
        var listOfWidgets = List<Widget>();
    
    
        for (var item in dataList) {
          containerWidth = item.expanded
              ? MediaQuery.of(context).size.width* 1
              :  MediaQuery.of(context).size.width * 0.30;
          listOfWidgets.add(GestureDetector(
            onDoubleTap: () {
              print("onDoubleTap");
              setState(() {
                for (var item in dataList)
                  item.expanded=false;
                item.expanded = !item.expanded;
              });
            },
            child: AnimatedContainer(
              curve: Curves.easeOut,
              duration: Duration(milliseconds: 100),
              color: Colors.red,
              width: containerWidth,
              margin: EdgeInsets.all(8),
              child: Center(
                child: Text(
                  item.title,
                  style: TextStyle(
                    color: Colors.white,
                  ),
                ),
              ),
            ),
          )); // TODO: Whatever layout you need for each widget.
        }
    
        return listOfWidgets;
      }
    }
    
    
    class DataModel {
      String title;
      bool expanded;
    
      DataModel(this.title) {
        expanded = false;
      }
    }