Welcome to the first Flutter design challenge of themobilecoder. Here, we find a beautiful design and try to write it up and implement it into an app.
The goal of design challenges is not to implement the full product itself, but instead make up the design in Flutter so everyone including me can learn and apply the learnings in our own apps.
For our first design challenge, we will implement a simple shopping page that contains a photo of the product, a favourite button, and a buy button. I found a great mock-up in Dribbble to illustrate this concept.
For our app, I will use a different photo and change a few bits in the content to make it a little more original.
After writing up the code for our challenge, here's what it looks like.
Let's start by defining the resources that we need for this challenge.
1. Colour Palette
The colours we used in this project are the following:
- Orange -
- Black -
- White -
The photo we will be using is from Unsplash by Tamara Bellis.
The font used from Dribbble is
Neogrotesk Pro but since it requires a license to use, I chose a font that looks similar called WorkSans
I will use an iPhone 14 simulator in this challenge, so all the padding dimensions will be appropriate for this phone's size.
Let's determine the different parts of this screen and how they are arranged. We have a full-screen photo behind a content box. This content box is on the same plane as the bottom bar which contains two buttons: the favourite button and the buy button.
Now that we have defined the main components of this screen, we can do a quick implementation to demonstrate this arrangement.
I use a
Scaffold widget to contain the components on this screen. I will use the scaffold's
bottomNavigationBar property to contain the buttons bar widget. Scaffold also has a
body property that contains the main content. For the
body, we will use a
Stack widget to contain two widgets: the image and the content container. We use a stack so we can put elements on top of each other.
Now it's time to replace each component with the right widgets.
Implementing the image widget
For the primary image, we will use an
Image.asset() widget. This is the best option for static images that are already included in the asset directory of your project.
Transform the image
That image seems a bit small, so we can transform its size and position it accordingly. To do this, wrap the
Image.asset() with a
To increase the size, we can use a
Transform.scale() and set the scale accordingly. To adjust the position of the image, we can use the
Transform.transalate() and move the image vertically so we can see the clothes we are selling clearly.
scale = 2.2 and
imageOffset = Offset(x = 0, y = 340) to achieve my desired outcome for an iPhone 14 screen.
The last thing to note is that the edges of the image should be rounded. Let's trim the corners to be rounded by using the
ClipRRect widget, which stands for ClipRoundedRectangle.
After doing these changes, we can make a reusable widget that accepts a scale, position offset, and the source image to use as parameters. I will name this
After updating the
main_screen.dart with the new widget we created, the screen should be updated with a bigger photo that highlights the product better.
Implementing the product content
The product content is the white container that contains the product name, brand, and description. Writing code for this would have been a simple
Container, but because of the curves found on the top left and top right corners, we cannot simply use a container.
Using the ClipPath widget
One approach to do these curved corners is to use the
ClipPath widget and write our own
CustomClipper<Path>. Check out the official tutorial for ClipPaths but for a simple explanation, the custom clipper should draw a rectangle base, with the top left curved clockwise, and the top right curved counter-clockwise.
The next thing to do is to create a
Container that has a minimum and maximum height and can contain a widget (Column of texts) that describes our product. Let's make this a reusable widget too and name it
Once we replace the purple box with this container, it should show a white box with our fancy corners on top.
Adding the description content
The content can be a simple
Column with three
Text widgets as its children. The important part here is the different text styles used for each text. As we have included the necessary font in this project (WorkSans), it is just a matter of using different
fontSize , and paddings in between.
Check out this
Column tutorial to know more about its properties.
After writing the code for this, we can make this a reusable widget and call it
DescriptionContent which accepts a product title, brand, and description.
We should now use this widget and put this as a child of the
CurvedCornerContainer that we just wrote. The screen should look much closer to our chosen design!
Implementing the buttons bar
The last component that we will write is the buttons bar. It contains two buttons laid out vertically, so we will use a
The favourite button is implemented using a
MaterialButton. To replicate the button in the design, we have to set the
shape property of the button to
CircleBorder which has a grey border with a very thin width.
For the icon itself, we use an
Icon widget that uses the
Icons.favorite as the image. To make this image smaller, use
Padding to push the image into a smaller size.
The same thing will be used for the
BuyButton. We use a
MaterialButton to wrap a
Text widget. In order to get the desired shape, we use a
RoundedRectangleBorder as the
shape property of the
We also need to make sure that the button colour is black and the text should be white.
Buttons bar implementation
As mentioned before, the buttons bar will be implemented using a
Row widget to hold the buttons horizontally.
One thing to note here is that the
BuyButton fills up the remaining space next to the
FavouriteButton. To do this behaviour, we need to wrap the
BuyButton with an
Expanded widget to fill up the remaining space in the
We also need to put appropriate
Padding so the sizes and spacings will look more natural.
Once we replace the
bottomNavigationBar with the
ButtonsBar widget, our app will look almost the same as our design inspiration.
White border outline
In the original design, there is a white outline along the border of the screen. We produce the same effect by adding a
Padding to our
Stack of widgets.
Main screen implementation
Once we have converted everything, our
MainScreen widget should be complete. Mainly, it is a
Scaffold that consists of a customised
bottomNavigationBar and a
Stack that consists of the product image and the content description.
This side-by-side comparison tells us that our design challenge was a success! This product page was implemented without using external libraries and was built using widgets included in the Flutter library.
As you get more experienced with Flutter, you will learn that hard-coded values do not work in a real-world setting. While the values that we use in this project worked on an iPhone 14 device, this will not look as good in an iPhone SE, or worse, on a tablet.
These considerations are out of scope for this design challenge but are something to keep in mind when developing real apps.