Building a Tinder-like swiping interface in Flutter

Florian Abel
CodeX
Published in
10 min readJun 14, 2022

TL;DR: If you are only interested in the swiping functionality you can jump straight here, or check out the final project on GitHub.

Photo by Sanjay Mehra on Unsplash

Intro

In this article you will be guided step-by-step through the development of a tinder-like swiping interface with the Flutter framework.

What I like about the interface is the simplicity that allows a user to easily decide for or against a choice that is outlined in a Card. It can be useful for all types of Apps that need an easy YES/NO selection process.

The Flutter framework

Since this interface is best served on mobile devices and I was aiming at reusability across different platforms I decided to build this project in Google’s Flutter framework. It provides functionality to develop multi-platform applications that are usable on both Android and Apple phones, tablets, and even web applications from a single codebase.

Used Elements

The main components to building the swiping interface in this project are:

Furthermore, we will be using the dart:convert library and Model-Class serialization to read and decode some JSON data in order to populate the profile cards to swipe.

Setup

Please note, that this article is assuming a prior setup of your Flutter development environment. If you have not worked with Flutter before you can find a ton of free resources on how to get started in building your own applications on their official Flutter Website, here.

Creating the Flutter project

The process of setting up a Flutter project template differs a little bit, depending on the IDE you are working with. To make it best accessible and independent from any IDE I will be using the terminal for all steps throughout this article.

Let’s start with setting up a Flutter template project in our terminal:

flutter create swiping_interface
cd swiping_interface

Next, let’s clean up the template project and build the main skeleton of our app. Inside of ‘lib/main.dart’:

App-Skeleton

Importing Assets

In order to show some nice profile cards on the screen, we need data to populate the cards. For this project, we are going to store some profile pictures and additional profile information as JSON locally in the applications assets folder.

Creating the folder structure

Inside our application folder let’s create a new folder called ‘assets’ and inside the assets folder another folder called ‘json’ and one more called ‘profilepictures’.

Adding profile pictures

For the profile pictures, I went to Pexels, grabbed a few suitable profile pictures, and dropped them into the ‘profilepictures’ folder.

Adding profile data

Inside the ‘json’ folder we can create a ‘profiles.json’ like this:

Making the data available in your application

Inside the ‘flutter’ section of ‘pubspec.yaml’ we are adding an ‘assets’ section, telling Flutter which folders can be used as assets inside the application. More info on that topic can be found here.

Application-Layout

It’s time to bring a bit more on the screen now. Let’s start with a basic application outline.

Material widget and SafeArea

We are adding a Material widget for some basic styling and a SafeArea to make sure our App is not extending over unsafe boundaries such as nudges. Furthermore, let’s add a basic Container to hold all the elements from our layout.

Container styling and base layout

Now it’s time to fill this Container with a bit of styling and its first life, positioning it in the center of the screen and giving it a white background. Inside we are defining a Column with three child widgets:

  • A Container to hold a logo
  • The card that we want to swipe in the end
  • Another Container to hold a navigation

Since the ‘SwipeCard()’ is not defined yet, your IDE is probably going to show you an error at this stage. We are going to fix this in the next section.

Below you can see the complete ‘main.dart’ file.

Building the card-layout

In the last section, we have used a ‘SwipeCard()’ widget which has not been defined yet. Let’s start by creating another file inside the ‘lib’-folder and calling it ‘swipe_card.dart’.

Inside this file, we are going to build our Card-Interface for a user’s profile.

Base layout

First, we are creating e a base layout for the Card and then we will get to styling it in the next steps.

Inside our ‘main.dart’-file we are importing the SwipeCard widget, so Flutter can actually access it.

Displaying a profile picture

It might not look like much but we have created the groundwork for building up our interface and the swiping functionality. Now let’s go on to draw something on the screen:

First, we are adding a BoxDecoration widget to the Container’s decoration property, this gives us the possibility to add a background image to it and add some nice rounded corners.

However, since the Container widgets by default inherit the size of their children and we do not have a child widget here, we won’t see much on the screen yet. Therefore, we are adding an Expanded widget around the Container to make it fill all the available space.

Finally, to make this Card look nice we are also adding some margins.

If you go back a little bit you can see that so far we are occupying some space for the SafeArea, 60 pixels on top for a logo Container and 60 pixels on the bottom for a Navigation Container. Hence our SwipeCard Widget will now fill the remaining space available.

Application-Layout with Logo-Container on top, SwipeCard in the middle and Navigation-Container on the bottom
Application-Layout with Logo-Container on top, SwipeCard in the middle, and Navigation-Container on the bottom

Making SwipeCard reusable and adding more data to it

As you might have noticed in the last step, we have been hard-coding the path to our background image. This is making it impossible to reuse our widget for other profiles.

Making the widget reusable

First, let’s add some class variables and adjust our constructor. This way we can pass the necessary information into our widget and make it reusable. We are defining:

  • id
  • userName
  • userAge
  • userDescription
  • profileImageSrc

As you can see, the path for the image is not hardcoded anymore and depends on a path being passed into the Widget.

Later we are going to populate this Widget with the data we have defined earlier on in our JSON-File. For now, we are going to populate it manually, when we are invoking it at ‘main.dart’. So, please adjust SwipeCard() in your ‘main.dart’ to look like this:

If everything went well, your App should still function as before and look exactly the same.

Adding additional information to the layout

For the additional information, we are adding a Container, a Column, and two children with some styling.

  • The first child of the Column displays userName and userAge
  • The second child of the Column displays the user description. Make sure to add the overflow property so your user’s description does not overflow the available screen size.

If you are receiving an Error on the Colors Widget you might still be importing ‘flutter/widgets.dart’ instead of ‘flutter/material.dart’, just adjust that line and you are good to go.

Now your layout should look like this:

Final layout for the swiping interface
Final layout for the swiping interface

Building the swipe functionality

After we have finalized the layout it is now time to add some functionality to our interface.

In order to swipe through a stack of profiles we are going to need a few things:

  • A stack of profiles that we can swipe through
  • A way to swipe our profile cards left and right and to surface the card below
  • Some container to understand the swiping gesture and what to do afterward

The swiping interface container

We are going to create a new stateful widget, that holds all the necessary information and keeps track of what to show to the user.

In this article, I am not covering the details of stateless and stateful widgets. If this concept is new or unclear to you, please have a deeper look here.

First, we are creating a new file ‘swipe_interface.dart’, and are setting up the basis for our stateful widget. For the moment we are using our previously build SwipeCard widget as the only child and are replacing SwipeCard inside ‘main.dart’ with our newly created SwipingInterface.

Replaced SwipeCard() with SwipeInterface(), which in turn holds SwipeCard() as a child widget

Populating a stack of profile cards from our profiles.JSON file

We have made our SwipeCard widget reusable, but the data that we use to populate it is still hard-coded. Let’s change that and create a list of profiles from our JSON-file, that we can then use to populate the SwipeCard with data.

We are creating a new file called ‘profile.dart’ holding the Profile Class. Within this class we are creating a factory constructor to build a Profile object from JSON data:

For more information on the factory constructor, you can read here and for more information on JSON and serialization in Flutter, you can read here.

With this Profile Class available we can now easily create Profile Objects from JSON data. This is what we are going to do in our SwipeInterface, or actually we are going to create a list of Profile Objects.

Inside of our SwipeInterfaceState we are:

  • Defining a list of type Profile, that we manually pre-populate with two entries (more on that later).
  • Defining a function to load the data from our profiles.json file in assets, then creating a list of Profiles from it, and finally updating our profiles variable with it.
  • Calling this function from the constructor, to fetch the data and create our list of profiles on widget build.

Next, we are replacing the hard-coded data for SwipeCard with data from our list of profiles. And since we are handling a list of data, we are going to need a counter to indicate which profile should be loaded.

Now we are populating the SwipeCard widget from the list of profiles based on our counter.

Here you can see the full file for reference:

Now, our app should load all data from the JSON-file you have defined and show the first entry on the screen.

Adding the swipe functionality to the stack of profile cards

Now that we have all the building blocks in place, it is time to finally add the swiping interaction, using the Draggable and LayoutBuilder widgets, which cover a lot of the desired functionality out of the box.

  • The Draggable Widget can be dragged around the screen and show different states in order to give feedback on the dragging process.
  • The LayoutBuilder Widget provides its parents’ constraints and can therefore be used to set constraints based on the parents’ size.

At first, we are going to replace our static SwipeCard widget with a LayoutBuilder that returns a Draggable Widget.

Draggable comes with a bunch of properties. Three of them indicate different UI elements being used:

  • feedback → Element that gets dragged around (For us, this is the current profile card).
  • childWhenDragging → Element that is shown in the original place of the Widget (For us this is the card that is hidden under the current profile card).
  • child → Element that is shown initially, before the drag process is started (For us this is the current profile card).

For the feedback property, we are going to wrap our SwipeCard in a SizedBox widget. This gives us the possibility to define its height and width properties, based on the constraints provided by the LayoutBuilder. We need to do this because there seems to be a persisting bug with the feedback property, not providing constraints, and also not updating after rendering.

Most likely your App will look something like this now:

The problem here is based on the Expanded widget, which currently expands the SwipeCard as far as possible. Since we are using a LayoutBuilder now to wrap our Draggable and SwipeCards, we need to use the Expanded widget around the LayoutBuilder instead.

Now we can already swipe the profile cards as we please and the only thing missing is some kind of logic to utilize the swiping gestures.

Note: Here you can see, that the styling of the feedback card is different than the original. This is most likely also caused by the aforementioned bug.

Building logic to utilize swiping gestures

We want the app to notice that a user has “liked” or “not liked” a profile, do with that information whatever it should do, and then show the next profile in the stack.

Draggable has a callback function called ‘onDragEnd’ that we can utilize. It is called once the drag movement has finished and it provides us with the offset in x and y directions (dx and dy).

We are going to check the offset in the x-direction (dx) and if it goes beyond a defined threshold, we will call the appropriate function to deal with it.

First, let’s define a threshold and some methods:

Next, inside of Draggable, let’s call onDragEnd and pass dx:

Here, you can see the final version of the SwipeInterface widget:

Conclusion

Now, you can be proud of your very own swiping interface, built in Flutter. It is not perfect and still has a few corners and edges. I am sure there are more/different ways of building this and some might be better suited than others also depending on the concrete requirements you are having for your project. I hope it gives you a great start on experimenting with this type of interface and that you can build on top of it.

I’d be happy to hear about your experiences and/or where you would take another way in building this. Please feel free to hit me up in the comments section or on Twitter (@florian_abel_).

--

--

Florian Abel
CodeX
Writer for

Techie & Builder | Python, Flutter, Machine Learning/Data Science