Flutter Horizontal Listview with a Snap Effect

Last updated Feb 01, 2021

How to create a list of cards scrolling horizontally with snap to fit effect when swiped either from left or right. 

In this post we will learn how to create Horizontal Scollable Card with Snap effect.

For this Example i used  scroll_snap_list plugin.

 

This example  i havecreated a List of Data classes which contains Image and Count of items to be selected.

 

Let's get started

 

Step 1: Create a Flutter application

Step2: Add required plugin in pubspec.yaml file.

dependencies:
  flutter:
    sdk: flutter
  scroll_snap_list:

 

Import plugin in dart file

import 'package:scroll_snap_list/scroll_snap_list.dart';

 

Step 3:  Create a Data class file which contains image path and item count variable

class Data{
  int count;
  String path;
  Data(this.count,this.path);

}

 

Step 4: Create UI to display the data items

Widget _buildItemList(BuildContext context, int index){
  if(index == data.length)
    return Center(
      child: CircularProgressIndicator(),
    );
  return Container(
    width: 200,
    child: Center(
      child: Container(
        height: 380,

        child: Card(
          color: Colors.white,
          child: Column(
            mainAxisAlignment: MainAxisAlignment.center,
            children: [
              (index==current)?Container(child:RaisedButton(

                child: Icon(Icons.delete),
                color: Colors.red,
                onPressed: () {
                  setState(() {
                    data.removeAt(index);

                  });
                },
              )):Container(),
              Card(
                elevation: 10,
                child: Container(

                  width: 200,
                  height: 250,
                  child:
                  Image.network(data[index].path,scale: 1,fit: BoxFit.cover,),
                ),
              ),
              (index==current)?Row(
                crossAxisAlignment: CrossAxisAlignment.center,
                mainAxisAlignment: MainAxisAlignment.spaceBetween,
                children: [
                Container(
                  width: 50,
                  child: RaisedButton(

                    child: Icon(Icons.add),
                    color: Colors.green,
                    onPressed: () {
                      setState(() {
                        if(data[index].count<10)
                          data[index].count=data[index].count+1;
                      });
                    },

                  ),
                ),
                Text("${data[index].count}",style: TextStyle(color: Colors.blue,fontSize: 16),),
                Container(width: 50,
                  child: RaisedButton(

                    child: Icon(Icons.exposure_minus_1),
                    color: Colors.red,
                    onPressed: () {

                      setState(() {
                        if(data[index].count>0)
                          data[index].count=data[index].count-1;
                      });
                    },
                  ),
                )
              ],):Container()
            ],
          ),
        ),
      ),
    ),
  );
}

 

Step 5:  Now its time  to add our List data to ScrollSnapList widget.

This widget will handle the list scrolling and make snap animation effect for the current list item.

 

ScrollSnapList(
  itemBuilder: _buildItemList,
  onItemFocus: (pos){
    setState(() {
      current=pos;
    });
    print('Done! $pos');
  },
  itemSize: 200,
  dynamicItemSize: true,
  onReachEnd: (){
    print('Done!');
  },
  itemCount: data.length,
)

 

This  ScrollSnapList widget has property called itemBuilder which will take the data as input.

 

Step 6: Run Application

 

 Flutter Horizontal Listview with a Snap Effect

 

 

Complete Example code

 

import 'package:flutter/material.dart';
import 'package:scroll_snap_list/scroll_snap_list.dart';

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

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      debugShowCheckedModeBanner: false,
      home: DemoApp(),
      theme: ThemeData(
        brightness: Brightness.dark,
      ),
    );
  }
}

class DemoApp extends StatefulWidget {
  @override
  _DemoAppState createState() => _DemoAppState();
}

class _DemoAppState extends State<DemoApp> {

  int current=0;

  List<Data> data = [
    Data(0,
    "https://img.freepik.com/free-photo/milford-sound-new-zealand-travel-destination-concept_53876-42945.jpg"),
  Data(0,"https://watchandlearn.scholastic.com/content/dam/classroom-magazines/watchandlearn/videos/animals-and-plants/plants/what-are-plants-/What-Are-Plants.jpg"),
  Data(0,"https://encrypted-tbn0.gstatic.com/images?q=tbn:ANd9GcRc7drAdH_rr-5-s1dR37nexpspDiygTjd_eg&usqp=CAU"),
  Data(0,"https://images-na.ssl-images-amazon.com/images/I/51Gguy1yh9L.jpg"),
  Data(0,"https://nestreeo.com/wp-content/uploads/2020/03/Pyrostegia_venusta.jpg"),
  Data(0,"https://encrypted-tbn0.gstatic.com/images?q=tbn:ANd9GcQW7IvtmZDCGOoFuqg5s7QWSX7sWpf3bqZcsQ&usqp=CAU"),
    Data(0,"https://images-na.ssl-images-amazon.com/images/I/51Gguy1yh9L.jpg"),
    Data(0,"https://nestreeo.com/wp-content/uploads/2020/03/Pyrostegia_venusta.jpg"),
    Data(0,"https://encrypted-tbn0.gstatic.com/images?q=tbn:ANd9GcQW7IvtmZDCGOoFuqg5s7QWSX7sWpf3bqZcsQ&usqp=CAU"),
  ];

  Widget _buildItemList(BuildContext context, int index){
    if(index == data.length)
      return Center(
        child: CircularProgressIndicator(),
      );
    return Container(
      width: 200,
      child: Center(
        child: Container(
          height: 380,

          child: Card(
            color: Colors.white,
            child: Column(
              mainAxisAlignment: MainAxisAlignment.center,
              children: [
                (index==current)?Container(child:RaisedButton(

                  child: Icon(Icons.delete),
                  color: Colors.red,
                  onPressed: () {
                    setState(() {
                      data.removeAt(index);

                    });
                  },
                )):Container(),
                Card(
                  elevation: 10,
                  child: Container(

                    width: 200,
                    height: 250,
                    child:
                    Image.network(data[index].path,scale: 1,fit: BoxFit.cover,),
                  ),
                ),
                (index==current)?Row(
                  crossAxisAlignment: CrossAxisAlignment.center,
                  mainAxisAlignment: MainAxisAlignment.spaceBetween,
                  children: [
                  Container(
                    width: 50,
                    child: RaisedButton(

                      child: Icon(Icons.add),
                      color: Colors.green,
                      onPressed: () {
                        setState(() {
                          if(data[index].count<10)
                            data[index].count=data[index].count+1;
                        });
                      },

                    ),
                  ),
                  Text("${data[index].count}",style: TextStyle(color: Colors.blue,fontSize: 16),),
                  Container(width: 50,
                    child: RaisedButton(

                      child: Icon(Icons.exposure_minus_1),
                      color: Colors.red,
                      onPressed: () {

                        setState(() {
                          if(data[index].count>0)
                            data[index].count=data[index].count-1;
                        });
                      },
                    ),
                  )
                ],):Container()
              ],
            ),
          ),
        ),
      ),
    );
  }

  @override
  void initState() {
    // TODO: implement initState
    super.initState();
    current=0;
  }
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      backgroundColor: Colors.grey,
      appBar: AppBar(
        backgroundColor: Colors.pinkAccent,
        title: Text('Horizontal list',style: TextStyle(color: Colors.white),),
        centerTitle: true,
      ),
      body: Container(
        child: Column(
          children: [
            Expanded(
                child: ScrollSnapList(
                  itemBuilder: _buildItemList,
                  onItemFocus: (pos){
                    setState(() {
                      current=pos;
                    });
                    print('Done! $pos');
                  },
                  itemSize: 200,
                  dynamicItemSize: true,
                  onReachEnd: (){
                    print('Done!');
                  },
                  itemCount: data.length,
                )
            ),
          ],
        ),
      ),
    );
  }
}

class Data{
  int count;
  String path;
  Data(this.count,this.path);

}

 

Also read Flutter Dynamic Expansion Listview Example

 

 

Article Contributed By :
https://www.rrtutors.com/site_assets/profile/assets/img/avataaars.svg

4222 Views