Here is the GitHub link for this project. In this project, we will be implementing a Tinder-like swipe feature for the Android/IOS App in Flutter Framework.
App Preview
What Motivated me to do this project – An Introduction
Many of the prominent apps these days contain a swipe-like feature to put items in different buckets. Whether it is a Dating-app, TikTok-like app, News-app, each of them is implementable with swipe features. Like, dislike, super-like, keep, discard, add-to-list, remove-from-list are some of the keywords to consider while implementing such features. Whatever you name it, you should know how things work from inside, keeping the engineering aspect of such features in mind. This project will help you to get up and running with such features as quickly as possible. If you want to check out my previous flutter-app, you can read here. In this project, we will be implementing a Tinder-like swipe feature for the Android/IOS App using Google’s Flutter Framework.
Prerequisite
Basic working knowledge of the most common flutter widgets.
Google’s Flutter Framework
Google started working on the Dart project way before the Flutter arrival. The main motto of this framework is to revolutionise the way we think about the design of applications. Also, this framework provided the programmers the facility of one codebase, which runs on the web, desktop, Android, and IOS. And that too at 60 fps, which gives the designer the confidence in building multi-platform apps with native performance.
Glossary
Stateless Widget:
These widgets do not depend on any mutable configurations, they build once using fixed parameters, and that’s it. The parameters can not change after that. They are ideal for buttons, icons, etc. They do not hold any state information; we can not use them to store any piece of information.
Stateful Widget:
They are used to store state-based information; their information(stored data) do not die on refresh. It survives hot reload and refresh. They are ideal when we need to store any data for some time.
Scaffold:
Scaffold widget makes Flutter developer’s life easy by providing APIs for drawers, BottomNavigationBar, FloatingActionButton, AppBar, etc. They are greedy, which means they occupy the whole screen available to them.
AppBar:
This widget is useful in building the top of the screen. They contain space for leading widgets, title, and action buttons. We are also allowed to add things (widgets) in the flexible area, and bottom of the App Bar.
ListView:
ListView widget is a scrollable list of widgets arranged linearly. It is useful in scrolling over any combination of linearly arranged widgets. We are using ListTile Widgets in ListView displays in this project.
ListTile:
ListTile widget is a row which contains space of text, with additional blocks for leading and trailing icons.
Navigator:
This widget manages a set of child widgets in a stack-based manner; we use this widget to jump from one page to another.
Dismissible class:
A widget in a flutter framework that can be dismissed by dragging in the indicated direction.
Steps
Step 1:
Add the code given in this GitHub-gist to your “pubspec.yaml” file. Pubspec lists all of the dependencies that the project needs. Be sure to write “uses-material-design: true “ in the pubspec file. In addition, you can add any other library you want to use in the dependencies section. We don’t need any external libraries because we are building a fairly basic app with a swiping feature.
name: party_invite | |
description: A new Flutter project. | |
version: 1.0.0+1 | |
environment: | |
sdk: ">=2.1.0 <3.0.0" | |
dependencies: | |
flutter: | |
sdk: flutter | |
random_color: any | |
cupertino_icons: ^0.1.2 | |
dev_dependencies: | |
flutter_test: | |
sdk: flutter | |
flutter: | |
uses-material-design: true |
Step 2:
This step sets up the root widget “MyApp” this returns a MaterialApp, which is a built-in widget provided to us using the Flutter Framework. We have set up the primarySwatch color to “Colors.blue.” Set the initialRoute as /, which will be the homepage of our app. We can also set the routes in a dictionary manner using routes attribute. We have two larger widgets PartyInvite and InvitePage, which we will discuss later.
import 'package:flutter/material.dart'; | |
void main() => runApp(MyApp()); | |
class MyApp extends StatelessWidget { | |
@override | |
Widget build(BuildContext context) { | |
return MaterialApp( | |
title: 'Party Invite', | |
theme: ThemeData( | |
primarySwatch: Colors.blue, | |
), | |
initialRoute: '/', | |
routes: { | |
'/': (context) => PartyInvite(), | |
'/invites': (context) => InvitePage(), | |
}, | |
); | |
} | |
} |
Step 3:
This step sets up the PartyInvite Widget, which is the main page of our app. This Stateless widget returns a Scaffold widget, in this widget, we describe the look of the appBar using the attribute. The appBar contains a GestureDetector, which helps us to transition to the next page, with its child being an Icon. For the body, we are using the MyBody widget, which we will learn about in the next steps.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
List<String> lst = List<String>();
class PartyInvite extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
backgroundColor: Colors.orange,
actions: <Widget>[
GestureDetector(
onTap: (){
Navigator.pushNamed(context, '/invites', arguments: lst);
},
child: Container(
padding: EdgeInsets.all(16),
child: Icon(Icons.content_paste, color: Colors.black,)
),
),
],
title: Center(
child: Text(
'Party Invite',
style: TextStyle(
fontFamily: 'cursive',
fontSize: 32,
color: Colors.black,
),
)
),
),
body: MyBody(),
);
}
}
List<String> lst = List<String>(); | |
class PartyInvite extends StatelessWidget { | |
@override | |
Widget build(BuildContext context) { | |
return Scaffold( | |
appBar: AppBar( | |
backgroundColor: Colors.orange, | |
actions: <Widget>[ | |
GestureDetector( | |
onTap: (){ | |
Navigator.pushNamed(context, '/invites', arguments: lst); | |
}, | |
child: Container( | |
padding: EdgeInsets.all(16), | |
child: Icon(Icons.content_paste, color: Colors.black,) | |
), | |
), | |
], | |
title: Center( | |
child: Text( | |
'Party Invite', | |
style: TextStyle( | |
fontFamily: 'cursive', | |
fontSize: 32, | |
color: Colors.black, | |
), | |
) | |
), | |
), | |
body: MyBody(), | |
); | |
} | |
} |
Step 4:
Set the list of strings as given below in the GitHub-gist, we will be using this later in the project to implement persons in a list view. Also, declare the func function definition, we will use this in the coming steps.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
List<String> items = <String>[
'Adam',
'Eve',
'Robert',
'Taylor',
'Micheal',
'Rick',
'Morty',
'Ted',
'Marshall',
'Barney',
'Swarley',
'Robin',
'Dora',
'Sandy',
];
typedef func = void Function(int index);
List<String> items = <String>[ | |
'Adam', | |
'Eve', | |
'Robert', | |
'Taylor', | |
'Micheal', | |
'Rick', | |
'Morty', | |
'Ted', | |
'Marshall', | |
'Barney', | |
'Swarley', | |
'Robin', | |
'Dora', | |
'Sandy', | |
]; | |
typedef func = void Function(int index); |
Step 5:
These steps describe the Stateful widget MyBody. It contains the list view of the persons we want to invite/not invite to our secret party. The call function is called when we wish to remove an item at a particular index from the list, do not forget to call setState inside call to update the display of our list. The build function builds a Person list using “Listview.builder” function, we push the callback function as an argument to the Person Widget.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
class MyBody extends StatefulWidget {
@override
_MyBodyState createState() => _MyBodyState();
}
class _MyBodyState extends State<MyBody> {
void call(int index){
setState(() {
items.removeAt(index);
});
}
@override
Widget build(BuildContext context) {
return ListView.builder(
itemCount: items.length,
itemBuilder: (context, index) {
return Person(name: '${items[index]}', idx: index, cb: call);
},
);
}
}
class MyBody extends StatefulWidget { | |
@override | |
_MyBodyState createState() => _MyBodyState(); | |
} | |
class _MyBodyState extends State<MyBody> { | |
void call(int index){ | |
setState(() { | |
items.removeAt(index); | |
}); | |
} | |
@override | |
Widget build(BuildContext context) { | |
return ListView.builder( | |
itemCount: items.length, | |
itemBuilder: (context, index) { | |
return Person(name: '${items[index]}', idx: index, cb: call); | |
}, | |
); | |
} | |
} |
Step 6:
This step describes the Person Stateless widget. The constructor of this widget consists of three parameters: name, callback function, and an index. The build function of this widget returns a widget “Container,” which contains a Dismissible widget. We are implementing left and right swipe, so we need to set background (for right swipe), and “secondaryBackground” (for left swipe), set the color, alignment, padding, and child(Icon) as given in the code, instead of the Icon widget you can also choose to put a text widget if that suits your need remember “Almost Everything in Flutter is a widget” so you have the complete independence to put anything you desire.
Child of this Dismissible widget is a listTile with a leading WhatsApp/Gmail like circleAvatar(with user initials), and a text title which shows simply the name of the Person. We are checking the direction of the dismission using the “onDismissed” property of the widget. “DismissDirection.startToEnd” tells us about the right-swipe, we can implement our custom swipe if we want. Based on the type of swipe, we can put the data on different lists/buckets. Person class implements the core code for the tinder-like swiping feature.
Therefore, it is the most important part of this app, so please focus on this part more.
class Person extends StatelessWidget { | |
Person({this.name, this.cb, this.idx}); | |
final String name; | |
final func cb; | |
final int idx; | |
@override | |
Widget build(BuildContext context) { | |
//RandomColor _randomColor = RandomColor(); | |
//Color _color = _randomColor.randomColor(colorBrightness: ColorBrightness.light); | |
return Container( | |
//decoration: BoxDecoration(color: _color), | |
child: Dismissible( | |
key: Key(name), | |
background: Container( | |
color: Colors.green, | |
padding: EdgeInsets.symmetric(horizontal: 10), | |
alignment: AlignmentDirectional.centerStart, | |
child: Icon(Icons.check_box), | |
), | |
secondaryBackground: Container( | |
color: Colors.redAccent, | |
padding: EdgeInsets.symmetric(horizontal: 10), | |
alignment: AlignmentDirectional.centerEnd, | |
child: Icon(Icons.backspace), | |
), | |
onDismissed: (DismissDirection d){ | |
if(d == DismissDirection.startToEnd){ | |
//print("Add"); | |
cb(idx); | |
lst.add(name); | |
print(lst); | |
} | |
else{ | |
cb(idx); | |
//print("Delete"); | |
} | |
}, | |
child: ListTile( | |
leading: CircleAvatar(child: Text(name[0]),), | |
title: Text(name, style: TextStyle(fontWeight: FontWeight.w800)), | |
)), | |
); | |
} | |
} |
Step 7:
These steps help us in setting up the “InvitePage” widget, which is the second page, and it displays the list of persons that we have right-swiped in the previous steps. It returns a Scaffold widget with orange-colored appBar and a body with MyInvites widget. MyInvite widget uses a similar list-builder approach to show the list of right-swiped individuals/invitees. We are obtaining the data from arguments using “ModalRoute.of(context).settings.arguments”. After that, we can get the data passed from the previous page.
class InvitePage extends StatelessWidget { | |
@override | |
Widget build(BuildContext context) { | |
return Scaffold( | |
appBar: AppBar( | |
backgroundColor: Colors.orange, | |
title: Center( | |
child: Text( | |
'Party Invite', | |
style: TextStyle( | |
fontFamily: 'cursive', | |
fontSize: 32, | |
color: Colors.black, | |
), | |
) | |
), | |
), | |
body: MyInvites(), | |
); | |
} | |
} | |
class MyInvites extends StatelessWidget { | |
@override | |
Widget build(BuildContext context) { | |
List<String> args = ModalRoute.of(context).settings.arguments; | |
print(args); | |
return ListView.builder( | |
itemCount: args.length, | |
itemBuilder: (context, index) { | |
return ListTile( | |
title: Text(args[index]), | |
leading: CircleAvatar(child: Text(args[index][0]),), | |
); | |
}, | |
);; | |
} | |
} |
Step 8:
Press the hot-reload functionality in your IDE, and viola! you have your own app with tinder-like swiping functionality. Play around with this code, it will help you to understand the working of the widgets involved. Try to put replace one widget with your own and see how the User-Interface changes, the possibilities are endless. In addition, you can use this source code and modify it to build your own custom app, the code for this app is provided on the GitHub Repository.
Conclusion
This project helps the user in the understanding of the inner machinations of Google’s Flutter framework. After reading this article, the user should be confident enough to implement this feature in their apps. You can use this code as a boilerplate for working on your custom swipe feature. I can’t wait to see what you build with this!
Learning Tools
This project is a starting point for a Flutter application.
A few resources to get you started if this is your first Flutter project:
For help getting started with Flutter, view the online documentation, which offers tutorials, samples, guidance on mobile development, and a full API reference. In this project, we will be implementing a Tinder-like swipe feature for the Android/IOS App in Flutter Framework.
Learning Strategies
- Use hot reload functionality for fast development time because it is one of the perks of using Dart language.
- Try experimenting with buttons, icons, and lists, and other widgets as it contains most of the things one can think of. Use Widget Catalog for doing some research about new widgets. For instance, I learned most of the techniques described here by reading from the catalog and experimenting the same.
- Always search for packages before implementing your own because most of the time, people have faced the challenges you are facing, and most probably, they made some libraries for help.
- Use pub.dev to search for existing packages, it will help you to be a better developer. In addition, you can read Learning dollar blogs to understand how Flutter apps work.
Reflective Analysis
After learning to use the Dismissible widget, I tried implementing this feature in my party-invite app. It helped me to understand the inner workings of the flutter widgets. I got to learn about Routes, Scaffold, GestureDetectors, and many more widgets. Swiping features are becoming too mainstream in modern app development if you want to learn how to implement your own swiping functionality this app will work as an entry-point in understanding the working of this feature. If you want to learn more about this, try reading about this widget here, it will help you in your app development, and save a lot of time which you would have used in implementing the custom-swipe features. This project gives you the overall idea of implementing your own tinder-like swiping feature in a flutter app.
Future Directions
- We can add a feature to add a new person dynamically using the Floating Action Button. After that, the user can click on the fab button to add a person.
- We can implement different buckets for different swipe directions, like upwards in the case of super-like. For instance, few apps provide a limited number of super-likes each day, you can implement this by a little modification in this code.
- One good extension idea is to add a delete icon that puts the person in none of the categories and just deletes the item from the list. However, it is not necessary in this case.
- Use firebase to remotely fetch users from the cloud-based on the user’s preference or by using some machine learning models. In other words, we can fetch the data on Demand from the cloud using pre-built ML models.
Here is the GitHub link for this project.
I can’t wait to see your app on Google Play Store.
Happy Fluttering!
We can implement the Swipe feature to enable to minimize the application
Another Extension Idea that I can Suggest is to implement the functionality of adding your
favorite person from the application by using the Swipe Feature
We can also enable the implementation of the Swipe Feature to share information to 3rd Party Applications
Thanks for your review! I hope you learned a thing or two about Flutter after reading this post.