Reputation: 340
I am exploring the possibility of having 2 cards per drag/swipe in a carousel element. [
Each carousel slide will showcase 2 cards linked to an individual review feature and 3 circle indicator at the bottom. Thinking of having 3 carousel slides, so it will be balanced.
So far, I only see references that is only one image carousel like this. I cannot re-create with adjusting the sample code to have 2 cards in one carousel slide. Hope you can show me how I can do the code?
Also, since I cannot find a reference or example for this, is it not advisable to do this intricate kind of carousel slide cards? I am newly learning Flutter, so I am not sure if this will make backend APIs tricky or what.
Upvotes: 3
Views: 3853
Reputation: 444
You can implement it by setting PageController
to a PageView and set viewportFraction
to a number less than 1.
Then put two cards on each page.
Here's the source code:
import 'package:flutter/material.dart';
void main() {
runApp(const MyApp());
}
class MyApp extends StatelessWidget {
const MyApp({Key? key}) : super(key: key);
@override
Widget build(BuildContext context) {
return const MaterialApp(
home: TwoCardPageView(),
);
}
}
class TwoCardPageView extends StatefulWidget {
const TwoCardPageView({Key? key}) : super(key: key);
@override
_TwoCardPageViewState createState() => _TwoCardPageViewState();
}
class _TwoCardPageViewState extends State<TwoCardPageView> {
final List<Item> _items = [
Item('A', Colors.red),
Item('B', Colors.yellow),
Item('C', Colors.green),
Item('D', Colors.purple),
Item('E', Colors.blue),
Item('F', Colors.pink),
Item('G', Colors.orange)
];
final PageController _pageController =
PageController(viewportFraction: 0.8, initialPage: 0);
double _page = 0;
@override
void initState() {
super.initState();
_pageController.addListener(() {
if (_pageController.page != null) {
_page = _pageController.page!;
setState(() {});
}
});
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: const Text('Two Card PageView'),
centerTitle: true,
),
body: Column(
children: [
SizedBox(
width: MediaQuery.of(context).size.width,
height: 200,
child: PageView.builder(
controller: _pageController,
itemCount: _items.length ~/ 2 + _items.length % 2,
itemBuilder: (context, index) {
return SizedBox(
child: Row(
children: [
Expanded(
child:
ItemBuilder(items: _items, index: index * 2)),
Expanded(
child: index * 2 + 1 >= _items.length
? const SizedBox()
: ItemBuilder(
items: _items, index: index * 2 + 1)),
],
),
);
}),
),
Row(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
for (int i = 0; i < _items.length ~/ 2 + _items.length % 2; i++)
Container(
margin: const EdgeInsets.all(2),
width: 10,
height: 10,
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(10),
border: Border.all(color: Colors.grey, width: 1.5),
color: _page - i > 1 || _page - i < -1
? Colors.transparent
: _page - i > 0
? Colors.grey.withOpacity(1 - (_page - i))
: Colors.grey.withOpacity(1 - (i - _page))),
)
],
)
],
),
);
}
}
class ItemBuilder extends StatelessWidget {
const ItemBuilder({
Key? key,
required List<Item> items,
required this.index,
}) : _items = items,
super(key: key);
final List<Item> _items;
final int index;
@override
Widget build(BuildContext context) {
return Container(
margin: const EdgeInsets.symmetric(horizontal: 8, vertical: 16),
height: 200,
color: _items[index].color,
child: Center(
child: Text(
_items[index].title,
style: const TextStyle(fontSize: 25),
)),
);
}
}
class Item {
final String title;
final Color color;
Item(this.title, this.color);
}
Upvotes: 3