Flutter Tutorial - Google Products App UI in Flutter

Flutter Tutorial - Google Products App UI in Flutter

In this Flutter Tutorial - Google Products App UI in Flutter, you'll learn: Initial setup, assets, and pubspec.yaml. Project Structure, UI Layout, AppBar, and Search Bar; Listing Page Widgets; Details Page Complete Layout, Background and Content; Fade Page Route, Hero Animations....

This is a follow along with the article for creating a Google Products App. You will be achieving something like below at the end of this article.

Empty Project

After downloading the empty project, you will have assets having images, icons and required fonts from the project. Also, you will have updated pubspec.yaml which has assets and fonts already added. When you run this project, you may find the dart version other than what I have. You can update pubspec.yaml with your dart version.

Product Listing UI Structure

Google Products App in Flutter

As per the blocks created above, we will create each of these blocks and assemble them in the products listing page.

Project Structure

Google Products App in Flutter

Products

As this is a product app, let’s create a Products class in models package. Product class has an image path for the product, name, description for some products, button text, background color for the block, product info and price. I have created 4 product objects also in the same class, which will be referred to in the product listing page.

import 'package:flutter/material.dart';

class Product {
  final String imagePath, name, description, buttonText, price, productInfo;
  final Color backgroundColor;

  Product({this.imagePath, this.name, this.description, this.buttonText, this.backgroundColor, this.price = "", this.productInfo = ""});
}

final Product pixelStand = Product(
  imagePath: "assets/images/pixelstand.webp",
  name: "Pixel stand",
  description: "New Release",
  buttonText: "",
  backgroundColor: Color(0xFFF9F9F9),
);

final Product dayDreamView = Product(
  imagePath: "assets/images/daydream.png",
  name: "DayDream View",
  description: "Premium",
  buttonText: "",
  backgroundColor: Color(0xFFE0DDFF),
);

final Product pixel = Product(
  imagePath: "assets/images/pixel.png",
  name: "Pixel 3a",
  description: "Meet the Google Pixel 3a.",
  buttonText: "Learn more",
  backgroundColor: Color(0xFFF5F5F5),
);

final Product stadia = Product(
    imagePath: "assets/images/stadia.png",
    name: "Google\nStadia",
    description: "New Release",
    buttonText: "CHECK OUT",
    backgroundColor: Color(0xFFFBE9EB),
    price: "69",
    productInfo: "Stadia is Google's new cloud based "
        "gaming platform that allows you to play your favorite git video games across screens instantly.");

Products Listing Page

AppBar

Create products_listing_page.dart in lib/ui/products_listing_page package like below. Using Scaffold and appBar in it. We will need screenHeight at a later stage in this screen. Use the ProductsListingPage as the home for MaterialApp in main.dart.

import 'package:flutter/material.dart';

class ProductsListingPage extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    final screenHeight = MediaQuery.of(context).size.height;
    return Scaffold(
      appBar: AppBar(
        elevation: 0.0,
        leading: Padding(
          padding: const EdgeInsets.all(16),
          child: Image.asset("assets/images/google_logo.png"),
        ),
        actions: <Widget>[
          Padding(
            padding: const EdgeInsets.all(16.0),
            child: Image.asset("assets/icons/menu.png"),
          )
        ],
      ),
    );
  }
}

Search Top Bar

Let’s create the body of Scaffold. We will have a SingleChildScrollView with Column as it’s a sole child. The first child of Column will be a Container having TextField. The container is used to give a rounded rectangular shape to the text field. Using InputBorder.none removes the default border of the Text Field. Once you have written the below code, you can select the Container and refactor it to a widget. Create a top_bar.dart in ui/products_listing_page package as TopBar is related to the listing page only and name the widget as TopBarWidget. You will have to manually resolve errors while importing, but that’s very easy.

body: SingleChildScrollView(
  child: Column(
    children: <Widget>[
      Container(
        margin: const EdgeInsets.symmetric(horizontal: 20, vertical: 10),
        decoration: BoxDecoration(
          color: Color(0xFFE0E0E0),
          borderRadius: BorderRadius.all(Radius.circular(30)),
        ),
        child: TextField(
          cursorColor: Colors.grey,
          style: TextStyle(fontSize: 16.0, color: Colors.black),
          decoration: InputDecoration(
              prefixIcon: Icon(
                Icons.search,
                color: Colors.grey,
                size: 16,
              ),
              border: InputBorder.none,
              hintText: "Search google products",
              hintStyle: TextStyle(color: Colors.grey, fontSize: 14.0)),
        ),
      ),
    ],
  ),
)
body: SingleChildScrollView(
  child: Column(
    children: <Widget>[
      TopBar(),
    ],
  ),
)

Google Products App in Flutter

Right Image Product Item Widget

As the name suggests, this is a product item widget where we will have an image on the right side. Create a file in ui/products_listing_page package named right_image_product_item_widget.dart.

Create a Container and give height as 30 percentage of the screen height, as it looks by the design. Whatever the screen size, this will scale itself based on that and you will be able to create responsive UI.

Let’s divide the widget into two parts using the Expanded widget in a Row. Left has 4/9 portion and the right one has 5/9 portion.

The left side has a column with text and a blue button. This button is used at one more place so let’s create that as a different widget called BlueButton in ui/products_listing_page package.

The right side has a rotated image, so using Transform rotate and positioned to shift the image a little down. Since we wanted to use the Positioned widget so I am wrapping that in Stack widget. Let’s see the updated code for products_listing_page.dart.


import 'package:flutter/material.dart';
import '../../models/product.dart';
import 'blue_button.dart';

class RightImageProductImageWidget extends StatelessWidget {
  const RightImageProductImageWidget({
    Key key,
    @required this.screenHeight,
    @required this.product,
  }) : super(key: key);

  final double screenHeight;
  final Product product;

  @override
  Widget build(BuildContext context) {
    return Container(
      padding: const EdgeInsets.only(left: 32),
      height: screenHeight * 0.3,
      color: product.backgroundColor,
      child: Row(
        mainAxisAlignment: MainAxisAlignment.spaceBetween,
        children: <Widget>[
          Expanded(
            flex: 4,
            child: Column(
              mainAxisAlignment: MainAxisAlignment.center,
              crossAxisAlignment: CrossAxisAlignment.start,
              children: <Widget>[
                Text(
                  product.description,
                  style: TextStyle(fontWeight: FontWeight.w900, fontSize: 17.0),
                ),
                SizedBox(
                  height: 10,
                ),
                BlueButton(product: product),
              ],
            ),
          ),
          Expanded(
            flex: 5,
            child: Stack(
              children: <Widget>[
                Positioned(
                  top: 50,
                  bottom: -50,
                  child: Transform.rotate(
                    angle: -0.2,
                    child: Image.asset(product.imagePath),
                  ),
                ),
              ],
            ),
          ),
        ],
      ),
    );
  }
}
import 'package:flutter/material.dart';
import 'package:googleproductsapp/models/product.dart';

class BlueButton extends StatelessWidget {
  const BlueButton({
    Key key,
    @required this.product,
  }) : super(key: key);

  final Product product;

  @override
  Widget build(BuildContext context) {
    return FlatButton(
      child: Text(
        product.buttonText,
        style: TextStyle(color: Colors.white, fontSize: 10, fontWeight: FontWeight.w600),
      ),
      onPressed: () {},
      color: Color(0xFF0000FF),
      shape: RoundedRectangleBorder(
        borderRadius: BorderRadius.all(
          Radius.circular(20),
        ),
      ),
    );
  }
}
body: SingleChildScrollView(
  child: Column(
    children: <Widget>[
      TopBar(),
      RightImageProductImageWidget(
        screenHeight: screenHeight,
        product: pixel,
      )
    ],
  ),
),

Google Products App in Flutter

Left Image Product Item Widget

As the name suggests, this is a product item widget where we will have an image on the left side. Create a file in ui/products_listing_page package named left_image_product_item_widget.dart.

Very similar to the above widget, we will have Container but this time height will be 25% of screen height as we can see in the design at the top of this article.

We will again use two Expanded widgets inside Row, but the left will have 5/9 portion and right will have 4/9 portion this time. Because the image is in a slightly bigger portion of the widget.

We won’t rotate the image this time because it is not required. Later in the article, you will find Hero widget being used to give navigation animations, once we have the details page.

The right side doesn’t need any introduction, it is similar to the above widget. Only one widget is extra i.e. a Text widget with “New Release” text.

import 'package:flutter/material.dart';

import '../../models/product.dart';
import 'blue_button.dart';

class LeftImageProductItemWidget extends StatelessWidget {
  const LeftImageProductItemWidget({Key key, @required this.screenHeight, @required this.product}) : super(key: key);

  final double screenHeight;
  final Product product;

  @override
  Widget build(BuildContext context) {
    return Container(
      padding: const EdgeInsets.symmetric(horizontal: 16),
      height: screenHeight * 0.25,
      color: Color(0xFFFBE9EB),
      child: Row(
        mainAxisAlignment: MainAxisAlignment.spaceBetween,
        children: <Widget>[
          Expanded(
            flex: 5,
            child: Stack(
              children: <Widget>[
                Align(
                  alignment: Alignment.center,
                  child: Image.asset(
                    product.imagePath,
                    height: 100,
                  ),
                ),
              ],
            ),
          ),
          Expanded(
            flex: 4,
            child: Padding(
              padding: const EdgeInsets.only(left: 16),
              child: Column(
                mainAxisAlignment: MainAxisAlignment.center,
                crossAxisAlignment: CrossAxisAlignment.start,
                children: <Widget>[
                  Text(
                    product.name,
                    style: TextStyle(fontWeight: FontWeight.w900, fontSize: 17.0),
                  ),
                  Text(
                    product.description,
                    style: TextStyle(color: Color(0xFF909090), fontSize: 8.0),
                  ),
                  SizedBox(
                    height: 5,
                  ),
                  BlueButton(
                    product: product,
                  ),
                ],
              ),
            ),
          ),
        ],
      ),
    );
  }
}
body: SingleChildScrollView(
  child: Column(
    children: <Widget>[
      TopBar(),
      RightImageProductImageWidget(
        screenHeight: screenHeight,
        product: pixel,
      ),
      LeftImageProductItemWidget(
        screenHeight: screenHeight,
        product: stadia,
      ),
    ],
  ),
)

Google Products App in Flutter

Two Products Item Widget

This widget contains two vertical product item widgets beside each other. The container’s height is again 25% the screen height. This is simplest of all the widgets, as it only has a Row having to equally expandable widgets. Each of the expandable has a vertical product item widget. Let’s see the code for two products item widget. It has two parameters product1 and product2.

import 'package:flutter/material.dart';
import '../../models/product.dart';

import 'vertical_product_item_widget.dart';

class TwoProductItemWidget extends StatelessWidget {
  const TwoProductItemWidget({
    Key key,
    @required this.screenHeight,
    @required this.product1,
    @required this.product2,
  }) : super(key: key);

  final double screenHeight;
  final Product product1, product2;

  @override
  Widget build(BuildContext context) {
    return Container(
      height: screenHeight * 0.25,
      child: Row(
        children: <Widget>[
          Expanded(
            flex: 1,
            child: VerticalProductItemWidget(
              product: product1,
            ),
          ),
          Expanded(
            flex: 1,
            child: VerticalProductItemWidget(
              product: product2,
            ),
          ),
        ],
      ),
    );
  }
}
body: SingleChildScrollView(
  child: Column(
    children: <Widget>[
      TopBar(),
      RightImageProductImageWidget(
        screenHeight: screenHeight,
        product: pixel,
      ),
      LeftImageProductItemWidget(
        screenHeight: screenHeight,
        product: stadia,
      ),
      TwoProductItemWidget(
        screenHeight: screenHeight,
        product1: pixelStand,
        product2: dayDreamView,
      ),
    ],
  ),
)

Of course, the above code will show error as we haven’t created a vertical product item widget yet. Let’s create that.

Vertical Product Item Widget

This is widget is easy as it has one Column wrapped in a Center widget to make all the contents in the center of the Column. Container wrapping all of this need not have height as the height of the container will be determined by the image height as we give it as 15% the screen height. We could have done it the same way as we did another widget, but I wanted to show you multiple ways to create the same type of Uis.

import 'package:flutter/material.dart';
import '../../models/product.dart';

class VerticalProductItemWidget extends StatelessWidget {
  final Product product;

  const VerticalProductItemWidget({Key key, this.product}) : super(key: key);

  @override
  Widget build(BuildContext context) {
    final screenHeight = MediaQuery.of(context).size.height;
    return Container(
      padding: const EdgeInsets.all(16),
      color: product.backgroundColor,
      child: Center(
        child: Column(
          children: <Widget>[
            Expanded(
                child: Image.asset(
                  product.imagePath,
                  height: screenHeight * 0.15,
                )),
            SizedBox(
              height: 5.0,
            ),
            Text(
              product.name,
              style: TextStyle(fontWeight: FontWeight.w800, color: Color(0xFF3B3B43), fontSize: 14),
            ),
            Text(
              product.description,
              style: TextStyle(fontWeight: FontWeight.w800, color: Color(0xFF3B3B43), fontSize: 8),
            ),
          ],
        ),
      ),
    );
  }
}

Now, if you run the app, we can see all the products, except the view all button. Google Products App in Flutter

Red Button

The red button is Raised Button that has padding on the left and the right sides so that it looks bigger. Button Text is passed in a parameter to make is more generic. Create widget package in ui package as red button is also used in detail screen, so it is good to make this in a separate package. Button text is always capital. Let’s see code for red button and output for listing page.

import 'package:flutter/material.dart';

class RedButton extends StatelessWidget {
  const RedButton({
    Key key,
    @required this.buttonText,
  }) : super(key: key);

  final String buttonText;

  @override
  Widget build(BuildContext context) {
    return RaisedButton(
      onPressed: () {},
      padding: const EdgeInsets.symmetric(horizontal: 96.0),
      color: Color(0xFFDA1D21),
      textColor: Colors.white,
      child: Text(buttonText.toUpperCase()),
      shape: RoundedRectangleBorder(
        borderRadius: BorderRadius.all(
          Radius.circular(30),
        ),
      ),
    );
  }
}
import 'package:flutter/material.dart';

import '../../models/product.dart';
import '../widgets/red_button.dart';
import 'left_image_product_item_widget.dart';
import 'right_image_product_item_widget.dart';
import 'top_bar.dart';
import 'two_product_item_widget.dart';

class ProductsListingPage extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    final screenHeight = MediaQuery.of(context).size.height;
    return Scaffold(
      appBar: AppBar(
        elevation: 0.0,
        leading: Padding(
          padding: const EdgeInsets.all(16),
          child: Image.asset("assets/images/google_logo.png"),
        ),
        actions: <Widget>[
          Padding(
            padding: const EdgeInsets.all(16.0),
            child: Image.asset("assets/icons/menu.png"),
          )
        ],
      ),
      body: SingleChildScrollView(
        child: Column(
          children: <Widget>[
            TopBar(),
            RightImageProductImageWidget(
              screenHeight: screenHeight,
              product: pixel,
            ),
            LeftImageProductItemWidget(
              screenHeight: screenHeight,
              product: stadia,
            ),
            TwoProductItemWidget(
              screenHeight: screenHeight,
              product1: pixelStand,
              product2: dayDreamView,
            ),
            RedButton(buttonText: "View all"),
          ],
        ),
      ),
    );
  }
}

Now that, we have added red button, we can also see SingleChildScrollView making sense in case of some mobiles. Google Products App in Flutter

The project should look like this now. Google Products App in Flutter

Product Detail Page

Let’s create a file in ui/products_detail_page named product_detail_page.dart. Since we haven’t added a way to navigate to detail screen, change your home to ProductDetailPage with stadia as product value for some time. Product Detail Page depends on product so it should accept product type parameter in constructor.

Product Detail Background

Clearly we can see, details screen has a background having a blue circle on top right, Google Text at some place in screen. These both things can be treated as the background of this screen.

All files now you create, have to be added to ui/products_detail_page package.

So, I am taking a Scaffold with no App Bar because, if we use App Bar from Scaffold, our background will be shown from bottom of App Bar, which is not the case here.

Background itself can be created with Stack because we have Google text on top of the blue circle. We will use screen width and height to position the circle and decide its width and height.

I have used a Google Logo image, instead of Text widget because if we give a very large font size to Text, it renders big in smaller phones as well, which makes it drop to two lines in smaller phones. Using image ensures that it will always be single line. I have applied color to the image as I could not find exact image.

I would like you to play with positioning of these images and understand more about positioning and size. Everything is explained in the video though. Do check it out to create concepts once and for all.


import 'package:flutter/material.dart';

class ProductDetailBackground extends StatelessWidget {
  const ProductDetailBackground({
    Key key,
    @required this.screenWidth,
    @required this.screenHeight,
  }) : super(key: key);

  final double screenWidth;
  final double screenHeight;

  @override
  Widget build(BuildContext context) {
    return Stack(
      fit: StackFit.expand,
      children: <Widget>[
        Positioned(
          left: screenWidth * 0.27,
          top: -screenWidth * 0.4,
          child: Container(
            width: screenWidth * 1.2,
            height: screenWidth * 1.2,
            decoration: BoxDecoration(
              shape: BoxShape.circle,
              color: Color(0xFF0000FF),
            ),
          ),
        ),
        Positioned(
          left: 20,
          right: 20,
          top: screenHeight * 0.2,
          child: Image.asset(
            "assets/images/google_text_logo.png",
            color: Color(0xFFECECEC).withOpacity(0.5),
          ),
        ),
      ],
    );
  }
}
import 'package:flutter/material.dart';

import '../../models/product.dart';
import 'product_detail_background.dart';
import 'product_detail_top_bar.dart';

class ProductDetailPage extends StatelessWidget {
  final Product product;

  const ProductDetailPage({Key key, @required this.product}) : super(key: key);

  @override
  Widget build(BuildContext context) {
    final screenWidth = MediaQuery.of(context).size.width;
    final screenHeight = MediaQuery.of(context).size.height;
    return Scaffold(
      body: Stack(
        children: <Widget>[
          ProductDetailBackground(screenWidth: screenWidth, screenHeight: screenHeight),
        ],
      ),
    );
  }
}

Google Products App in Flutter

Product Detail Outline

Google Products App in Flutter

Now, that we are ready with the background, we will create content. We will definitely use SingleChildScrollView and Column as it’s sole child.

First child of this will be ProductDetailTopBar

Product Detail Top Bar

To create the top bar, we use Container with definite height, margin from top and padding from left and right. The color should be transparent because we want to show the beautiful background we created above. Later in this article, we will add a Gesture Detector to the back button to navigate back to the listing page.

Create a file product_detail_top_bar.dart.

import 'package:flutter/material.dart';

class ProductDetailTopBar extends StatelessWidget {
  const ProductDetailTopBar({
    Key key,
  }) : super(key: key);

  @override
  Widget build(BuildContext context) {
    return Container(
      margin: const EdgeInsets.only(top: 32),
      padding: const EdgeInsets.symmetric(vertical: 16, horizontal: 16),
      height: 56,
      color: Colors.transparent,
      child: Row(
        children: <Widget>[
          Icon(
            Icons.arrow_back,
          ),
          Spacer(),
          Icon(
            Icons.search,
            color: Colors.white,
          ),
          SizedBox(
            width: 20,
          ),
          Image.asset(
            "assets/icons/menu.png",
            color: Colors.white,
            height: 30,
          ),
        ],
      ),
    );
  }
}
return Scaffold(
  body: Stack(
    children: <Widget>[
      ProductDetailBackground(
        screenHeight: screenHeight,
        screenWidth: screenWidth,
      ),
      SingleChildScrollView(
        child: Column(
          children: <Widget>[
            ProductDetailTopBar(),
          ],
        ),
      ),
    ],
  ),
);

Google Products App in Flutter

Product Content Widget

Whole content has padding from left and right. Since we are starting from the bottom of the Product detail top bar, we need a large spacing in between. So, use a sized box with height as 20% of the screen height.

Use the product’s image as the next child of Column with a height of 30% of the screen height.

Now, we need to show the price of the product. Use Row with MainAxisAlignment.spaceBetween and MainAxisSize.max to provide space between two widgets. To use $ symbol, you have to use “$”, because in dart $ is used to reference variables as well.

Then we have a product name and stadia logo. To give spacing between name and logo, I have used “\t\t\t” which will add some spacing between them. Better to use this instead of using the Sized Box widget.

I have created an Icon Title Widget, to layout icon and title one above each other. This widget is reusable, so create it in a different file.

Then, we have divider with height as 32, because of this, we will not need to add Padding widget to give spacing top and bottom of the divider.

We already have Red Button, use it in Row with having a Material Circular shape button.

Use this Product Content Widget on the Product Detail page and see the output.

import 'package:flutter/material.dart';
import 'package:googleproductsapp/widgets/red_button.dart';

import '../../models/product.dart';
import 'icon_title_widget.dart';

class ProductContentWidget extends StatelessWidget {
  final Product product;
  final screenHeight;

  const ProductContentWidget({Key key, this.product, this.screenHeight}) : super(key: key);

  @override
  Widget build(BuildContext context) {
    return Padding(
      padding: const EdgeInsets.symmetric(horizontal: 32.0),
      child: Column(
        crossAxisAlignment: CrossAxisAlignment.start,
        children: <Widget>[
          SizedBox(
            height: screenHeight * 0.2,
          ),
          Hero(
            tag: product.name,
            child: Image.asset(
              product.imagePath,
              height: screenHeight * 0.3,
            ),
          ),
          Row(
            mainAxisSize: MainAxisSize.max,
            mainAxisAlignment: MainAxisAlignment.spaceBetween,
            children: <Widget>[
              Text(
                "Starting*",
                style: TextStyle(
                  color: Color(0xFF909090),
                  fontSize: 10,
                  fontWeight: FontWeight.w900,
                ),
              ),
              RichText(
                text: TextSpan(children: [
                  TextSpan(
                    text: "\$ ",
                    style: TextStyle(color: Color(0xFF0000FF), fontSize: 10),
                  ),
                  TextSpan(
                    text: "${product.price}",
                    style: TextStyle(
                      color: Color(0xFF0000FF),
                      fontSize: 18,
                      fontWeight: FontWeight.w700,
                    ),
                  ),
                ]),
              ),
            ],
          ),
          SizedBox(
            height: 10,
          ),
          Row(
            children: <Widget>[
              Text(
                product.name.replaceAll("\n", " ") + "\t\t\t\t",
                style: TextStyle(
                  fontWeight: FontWeight.w900,
                  fontSize: 17.0,
                ),
              ),
              Image.asset(
                "assets/images/stadia_logo.png",
                height: 20,
              )
            ],
          ),
          SizedBox(
            height: 10,
          ),
          Text(
            product.productInfo,
            style: TextStyle(
              color: Color(0xFF909090),
              fontWeight: FontWeight.w300,
              fontSize: 14.0,
            ),
          ),
          SizedBox(
            height: 20,
          ),
          Center(
            child: Row(
              mainAxisSize: MainAxisSize.min,
              children: <Widget>[
                IconTitleWidget(imagePath: "assets/icons/create.png", title: "Create"),
                IconTitleWidget(imagePath: "assets/icons/connect.png", title: "Connect"),
                IconTitleWidget(imagePath: "assets/icons/discover.png", title: "Dicover"),
              ],
            ),
          ),
          Divider(
            color: Color(0xFFECECEC),
            thickness: 1,
            height: 32,
          ),
          Row(
            children: <Widget>[
              RedButton(
                buttonText: "Pre-order",
              ),
              Spacer(),
              Material(
                elevation: 4,
                color: Colors.white,
                shape: CircleBorder(),
                child: Icon(
                  Icons.add,
                  size: 35,
                  color: Color(0xFF0000FF),
                ),
              ),
            ],
          ),
        ],
      ),
    );
  }
}

return Scaffold(
  body: Stack(
    children: <Widget>[
      ProductDetailBackground(
        screenHeight: screenHeight,
        screenWidth: screenWidth,
      ),
      SingleChildScrollView(
        child: Column(
          children: <Widget>[
            ProductDetailTopBar(),
            ProductContentWidget(product: product, screenHeight: screenHeight),
          ],
        ),
      ),
    ],
  ),
);

Google Products App in Flutter

Screen Transition

After we have created the detail page, it’s time to add linking between these two screens. We will also create a custom Page Route, that will give us a fading effect when we navigate from one screen to another.

We will also add a Hero widget to the product image of left_image_product_item_widget.dart with the tag as the product’s name. Also, wrap the whole layout with Gesture Detector and provide navigation in the onTap method.

GestureDetector(
  onTap: () {
    Navigator.push(context, FadePageRoute(widget: ProductDetailPage(product: product)));
  },
  child: Container(
  ...
  ...
  ...
  ),
)


Expanded(
  flex: 5,
  child: Stack(
    children: <Widget>[
      Align(
        alignment: Alignment.center,
        child: Hero(
          tag: product.name,
          child: Image.asset(
            product.imagePath,
            height: 100,
          ),
        ),
      ),
    ],
  ),
)

In details page, ProductContentPage wrap product image with Hero.

Hero(
  tag: product.name,
  child: Image.asset(
    product.imagePath,
    height: screenHeight * 0.3,
  ),
)

Also, go to product_detail_top_bar.dart and wrap back arrow with GestureDetector -> onTap

GestureDetector(
  onTap: () {
    Navigator.pop(context);
  },
  child: Icon(
    Icons.arrow_back,
  ),
)

Fade Page Route

Do not forget to update main.dart with home as ProductsListingPage(), so that we can see the full result

import 'package:flutter/widgets.dart';

class FadePageRoute extends PageRouteBuilder {
  final Widget widget;

  FadePageRoute({this.widget})
      : super(
          pageBuilder: (
            BuildContext context,
            Animation<double> animation,
            Animation<double> secondaryAnimation,
          ) {
            return widget;
          },
          transitionsBuilder: ((
            BuildContext context,
            Animation<double> animation,
            Animation<double> secondaryAnimation,
            Widget child,
          ) {
            return FadeTransition(
              opacity: Tween(begin: 0.0, end: 1.0).animate(animation),
              child: child,
            );
          }),
        );
}

Do not forget to update main.dart with home as ProductsListingPage(), so that we can see the full result

Full Source Code

Video

Part 1 - Initial setup, assets, and pubspec.yaml. Project Structure, UI Layout, AppBar, and Search Bar

Part 2 Listing Page Widgets

Part 3 - Details Page Complete Layout, Background and Content

Part 4 - Fade Page Route, Hero Animations.

Part 5 - Comming soon

Flutter Dart Mobile-App

Bootstrap 5 Complete Course with Examples

Bootstrap 5 Tutorial - Bootstrap 5 Crash Course for Beginners

Nest.JS Tutorial for Beginners

Hello Vue 3: A First Look at Vue 3 and the Composition API

Building a simple Applications with Vue 3

Deno Crash Course: Explore Deno and Create a full REST API with Deno

How to Build a Real-time Chat App with Deno and WebSockets

Convert HTML to Markdown Online

HTML entity encoder decoder Online

Google's Flutter 1.20 stable announced with new features - Navoki

Google has announced new flutter 1.20 stable with many improvements, and features, enabling flutter for Desktop and Web

Top 25 Flutter Mobile App Templates in 2020

Flutter has been booming worldwide from the past few years. While there are many popular mobile app development technologies out there, Flutter has managed to leave its mark in the mobile application development world. In this article, we’ve curated the best Flutter app templates available on the market as of July 2020.

How To Succeed In Mobile App Wireframe Design?

This article covers everything about mobile app wireframe design: what to do and what not, tools used in designing a mobile or web app wireframe, and more.

What is Flutter and why you should learn it?

Flutter is an open-source UI toolkit for mobile developers, so they can use it to build native-looking Android and iOS applications from the same code base for both platforms. Flutter is also working to make Flutter apps for Web, PWA (progressive Web-App) and Desktop platform (Windows,macOS,Linux).

How much does it cost to make a Flutter app for your business?

Get a Free Quote on Android App Development, iPhone App Development, Ionic App Development, Video Development, ASO, SEO, Google Ads/Adwords, SEO for your app Idea.