Implementing Tinder-like card swipe in Flutter is quite easy. Flutter provides really powerful widgets and packages. Today, we are implementing Tinder-like card swipe in Flutter.
Also, in case you are planning to build dating mobile app, the swipe feature will be quite necessary.
You can use swipe_cards package to implement or it can also easily be done by without a package using a Draggable widget and other different approaches. In this blog, I am using swipe_cards. package.
Check our Flutter app development services page.
Breakdown:
I am breaking down the whole process into 2 steps:
- Creating a background to make the app look attractive.
- Swipe cards.
Implementation:
First, we will create background UI and then swipe cards. and at last, wrap them up with Stack widgets.
Let’s create our background UI.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 |
Widget backgroudCurve() { return Container( height: 350, width: MediaQuery .of(context) .size .width, decoration: const ShapeDecoration( shape: RoundedRectangleBorder( borderRadius: BorderRadius.only( bottomLeft: Radius.circular(75), bottomRight: Radius.circular(75), ) ), gradient: LinearGradient( colors: <Color>[ Color(0xFFFD0E42), Color(0xFFC30F31), ], ) ), child: const Padding( padding: EdgeInsets.only(top: 50, left: 20.0), child: Text("Explore", style: TextStyle( fontSize: 22, color: Colors.white, fontWeight: FontWeight.bold),), ), ); } |
For background UI, I have used some basic widgets. Linear gradient is used for box decoration but they looks same as they are really similar colors. You can use entirely different colors and it will still look good.
Now, let’s work on creating our swipe cards.
- Add swipe_cards package in your pub spec file.
- For images, I have a list of some random image urls.
1 2 3 4 5 6 7 |
List<String> images = [ "https://media.istockphoto.com/photos/young-beautiful-woman-picture-id1294339577?b=1&k=20&m=1294339577&s=170667a&w=0&h=_5-SM0Dmhb1fhRdz64lOUJMy8oic51GB_2_IPlhCCnU=", "https://encrypted-tbn0.gstatic.com/images?q=tbn:ANd9GcSHZmgTTTZhXAoNOiDirLHYLSTieoUrSsZFnnmyCDPs_8_KLtgbpXWdEI9AL2yiqWEvaP4&usqp=CAU", "https://image.shutterstock.com/image-photo/bowl-buddha-buckwheat-pumpkin-chicken-260nw-1259570605.jpg", "https://images.unsplash.com/photo-1543353071-873f17a7a088?ixlib=rb-1.2.1&ixid=MnwxMjA3fDB8MHxzZWFyY2h8Mnx8Zm9vZCUyMHByZXNlbnRhdGlvbnxlbnwwfHwwfHw%3D&w=1000&q=80", "https://image.shutterstock.com/image-photo/food-photography-260nw-578546905.jpg" ]; |
- Now add an empty list of swipe items and then add image list item in the swipe item list in initstate function.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 |
final List<SwipeItem> _swipeItems = []; @override void initState() { for (int i = 0; i < images.length; i++) { _swipeItems.add(SwipeItem( content: images[i], likeAction: () { }, nopeAction: () { }, superlikeAction: () { }, onSlideUpdate: (SlideRegion? region) async { print("Region $region"); } )); _matchEngine = MatchEngine(swipeItems: _swipeItems); } super.initState(); } |
- You can also add buttons and perform various functions using likeAction, nopeAction, and superlikeAction buttons.
- Now add SwipeCard widget and add image view. SwipeCards must have match engine, item builder, and onStackFinished function.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 |
Widget cardView() { return Center( child: SizedBox( height: MediaQuery .of(context) .size .height / 1.5 - 100, width: MediaQuery .of(context) .size .width / 1.5, child: SwipeCards( itemBuilder: (BuildContext context, int index) { return ClipRRect( borderRadius: BorderRadius.circular(10), child: Image.network( images[index], fit: BoxFit.fill, ) ); }, onStackFinished: () { _scaffoldKey.currentState?.showSnackBar(const SnackBar( content: Text("Stack Finished"), duration: Duration(milliseconds: 500), )); }, matchEngine: _matchEngine,) ), ); } |
- Now wrap both these functions in the stack widget and it’s done.
Result:
Full Code:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 |
import 'package:flutter/material.dart'; import 'package:swipe_cards/draggable_card.dart'; import 'package:swipe_cards/swipe_cards.dart'; void main() { runApp(const MyApp()); } class MyApp extends StatelessWidget { const MyApp({Key? key}) : super(key: key); @override Widget build(BuildContext context) { return MaterialApp( title: 'Flutter Demo', debugShowCheckedModeBanner: false, theme: ThemeData( primarySwatch: Colors.blue, ), home: const MyHomePage(), ); } } class MyHomePage extends StatefulWidget { const MyHomePage({Key? key}) : super(key: key); @override _MyHomePageState createState() => _MyHomePageState(); } class _MyHomePageState extends State<MyHomePage> { final List<SwipeItem> _swipeItems = []; late MatchEngine _matchEngine; GlobalKey<ScaffoldState> _scaffoldKey = GlobalKey(); List<String> images = [ "https://media.istockphoto.com/photos/young-beautiful-woman-picture-id1294339577?b=1&k=20&m=1294339577&s=170667a&w=0&h=_5-SM0Dmhb1fhRdz64lOUJMy8oic51GB_2_IPlhCCnU=", "https://encrypted-tbn0.gstatic.com/images?q=tbn:ANd9GcSHZmgTTTZhXAoNOiDirLHYLSTieoUrSsZFnnmyCDPs_8_KLtgbpXWdEI9AL2yiqWEvaP4&usqp=CAU", "https://image.shutterstock.com/image-photo/bowl-buddha-buckwheat-pumpkin-chicken-260nw-1259570605.jpg", "https://images.unsplash.com/photo-1543353071-873f17a7a088?ixlib=rb-1.2.1&ixid=MnwxMjA3fDB8MHxzZWFyY2h8Mnx8Zm9vZCUyMHByZXNlbnRhdGlvbnxlbnwwfHwwfHw%3D&w=1000&q=80", "https://image.shutterstock.com/image-photo/food-photography-260nw-578546905.jpg" ]; @override void initState() { for (int i = 0; i < images.length; i++) { _swipeItems.add(SwipeItem( content: images[i], likeAction: () { }, nopeAction: () { }, superlikeAction: () { }, onSlideUpdate: (SlideRegion? region) async { print("Region $region"); } )); _matchEngine = MatchEngine(swipeItems: _swipeItems); } super.initState(); } @override Widget build(BuildContext context) { return Scaffold( body: Stack( children: [ backgroudCurve(), cardView(), ], ), ); } Widget backgroudCurve() { return Container( height: 350, width: MediaQuery .of(context) .size .width, decoration: const ShapeDecoration( shape: RoundedRectangleBorder( borderRadius: BorderRadius.only( bottomLeft: Radius.circular(75), bottomRight: Radius.circular(75), ) ), gradient: LinearGradient( colors: <Color>[ Color(0xFFFD0E42), Color(0xFFC30F31), ], ) ), child: const Padding( padding: EdgeInsets.only(top: 50, left: 20.0), child: Text("Explore", style: TextStyle( fontSize: 22, color: Colors.white, fontWeight: FontWeight.bold),), ), ); } Widget cardView() { return Center( child: SizedBox( height: MediaQuery .of(context) .size .height / 1.5 - 100, width: MediaQuery .of(context) .size .width / 1.5, child: SwipeCards( itemBuilder: (BuildContext context, int index) { return ClipRRect( borderRadius: BorderRadius.circular(10), child: Image.network( images[index], fit: BoxFit.fill, ) ); }, onStackFinished: () { _scaffoldKey.currentState?.showSnackBar(const SnackBar( content: Text("Stack Finished"), duration: Duration(milliseconds: 500), )); }, matchEngine: _matchEngine,) ), ); } } |
Conclusion:
This is how we add swipe cards in flutter.
Thanks for reading this article
If I got something wrong, let me know in the comments. I would love to improve.
You can also read – https://mobikul.com/get-storage-in-flutter/
Reference link: https://pub.dev/packages/swipe_cards