Horizontally scrollable cards with Snap effect in flutter

DartFlutterFlutter LayoutFlutter AnimationFlutter Sliver

Dart Problem Overview


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

Each card has some spacing between them and fit to screen similar to below image

enter image description here

Apart from that these horizontally scrollable list elements should be contained inside a vertically scrollable list.

I all I am able to achieve is only displaying a list of horizontal scrolling cards after following example in flutter docs.

class SnapCarousel extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    final title = 'Horizontal List';

    return MaterialApp(
      title: title,
      home: Scaffold(
        appBar: AppBar(
          title: Text(title),
        ),
        body: Container(
          margin: EdgeInsets.symmetric(vertical: 20.0),
          height: 200.0,
          child: ListView(
            scrollDirection: Axis.horizontal,
            children: <Widget>[
              Container(
                width: 160.0,
                color: Colors.red,
              ),
              Container(
                width: 160.0,
                color: Colors.blue,
              ),
              Container(
                width: 160.0,
                color: Colors.green,
              ),
              Container(
                width: 160.0,
                color: Colors.yellow,
              ),
              Container(
                width: 160.0,
                color: Colors.orange,
              ),
            ],
          ),
        ),
      ),
    );
  }
}

Dart Solutions


Solution 1 - Dart

Use PageView and ListView:

import 'package:flutter/material.dart';

main() => runApp(MaterialApp(home: MyHomePage()));

class MyHomePage extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text('Carousel in vertical scrollable'),
      ),
      body: ListView.builder(
        padding: EdgeInsets.symmetric(vertical: 16.0),
        itemBuilder: (BuildContext context, int index) {
          if(index % 2 == 0) {
            return _buildCarousel(context, index ~/ 2);
          }
          else {
            return Divider();
          }
        },
      ),
    );
  }

  Widget _buildCarousel(BuildContext context, int carouselIndex) {
    return Column(
      mainAxisSize: MainAxisSize.min,
      children: <Widget>[
        Text('Carousel $carouselIndex'),
        SizedBox(
          // you may want to use an aspect ratio here for tablet support
          height: 200.0,
          child: PageView.builder(
            // store this controller in a State to save the carousel scroll position
            controller: PageController(viewportFraction: 0.8),
            itemBuilder: (BuildContext context, int itemIndex) {
              return _buildCarouselItem(context, carouselIndex, itemIndex);
            },
          ),
        )
      ],
    );
  }

  Widget _buildCarouselItem(BuildContext context, int carouselIndex, int itemIndex) {
    return Padding(
      padding: EdgeInsets.symmetric(horizontal: 4.0),
      child: Container(
        decoration: BoxDecoration(
          color: Colors.grey,
          borderRadius: BorderRadius.all(Radius.circular(4.0)),
        ),
      ),
    );
  }
}

Solution 2 - Dart

Screenshot:

enter image description here


If you don't want to use any 3rd party packages, you can simply try this:

class _HomePageState extends State<HomePage> {
  int _index = 0;

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(),
      body: Center(
        child: SizedBox(
          height: 200, // card height
          child: PageView.builder(
            itemCount: 10,
            controller: PageController(viewportFraction: 0.7),
            onPageChanged: (int index) => setState(() => _index = index),
            itemBuilder: (_, i) {
              return Transform.scale(
                scale: i == _index ? 1 : 0.9,
                child: Card(
                  elevation: 6,
                  shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(20)),
                  child: Center(
                    child: Text(
                      "Card ${i + 1}",
                      style: TextStyle(fontSize: 32),
                    ),
                  ),
                ),
              );
            },
          ),
        ),
      ),
    );
  }
}

Solution 3 - Dart

this is an old question, and I arrived here looking for something else ;-), but what WitVault was lookig is done easy with this package: https://pub.dev/packages/flutter_swiper

Demo image

The implementation:

Put the dependencies in pubsec.yaml:

dependencies:
   flutter_swiper: ^1.1.6

Import it in the page where you need it:

import 'package:flutter_swiper/flutter_swiper.dart';

In the layout:

new Swiper(
  itemBuilder: (BuildContext context, int index) {
    return new Image.network(
      "http://via.placeholder.com/288x188",
      fit: BoxFit.fill,
    );
  },
  itemCount: 10,
  viewportFraction: 0.8,
  scale: 0.9,
)

Solution 4 - Dart

To achieve the snap effect via ListView, just set the physics to PageScrollPhysics

const List<Widget> children = [  ContainerCard(),  ContainerCard(),  ContainerCard(),];
ListView.builder(
    scrollDirection: Axis.horizontal,
    physics: const PageScrollPhysics(), // this for snapping
    itemCount: children.length,
    itemBuilder: (_, index) => children[index],
  )

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionWitVaultView Question on Stackoverflow
Solution 1 - DartboformerView Answer on Stackoverflow
Solution 2 - DartCopsOnRoadView Answer on Stackoverflow
Solution 3 - DartDanielView Answer on Stackoverflow
Solution 4 - DartHazem MonirView Answer on Stackoverflow