Reuse a Flutter Widget by Extracting it into a Stateless Widget

Reuse a Flutter Widget by Extracting it into a Stateless Widget


There are cases that we want to reuse our widget. For example we have a padding that contains a material button, This type of button which has the same design for different screens has the styles except for color, title, and  method.

We can extract a widget and have its own stateless widget so that we can call it and change its properties according to what we need, take a look at our example. We have Login nad Register button but they have different title, colors and functionalities.

If we analyze, we know that we need 3 dynamic variables for it; 
1. Color variable
2. String variable for button title
3. Function variable for the button's onPressed callback.


Let Us Say that the following is a widget that we're going to use multiple times.



Padding(
              padding: EdgeInsets.symmetric(vertical: 16.0),
              child: Material(
                elevation: 5.0,
                color: Colors.lightBlueAccent,
                borderRadius: BorderRadius.circular(30.0),
                child: MaterialButton(
                  onPressed: () {
                    //Go to login screen.
                    Navigator.pushNamed(context, LoginScreen.id);
                  },
                  minWidth: 200.0,
                  height: 42.0,
                  child: Text(
                    'Log In',  
                  ),
                ),
              ),
            ),


In your visual studio code find the widget you use multiple times. Clicn on it then a bulb will show at left, click the bulb then select extract widget



It will ask for the class name, in our case we named it RoundedButton



You will see that the widget will be replaced by a class RoundedButton() and a stateless widget is created at the bottom



We don't need the constructor so just remove the following
  // const RoundedButton({
  //   Key key,
  // }) : super(key: key);


We're going to create our own constructor that is going to initialize 3 properties. We need the onpressed to be required so just add @required

  RoundedButton({this.title,this.colour,@required this.onPressed});

  final Color colour;
  final String title;
  final Function onPressed; 


Now We're going to update the properties of the MaterialButton to be dynamic. This is now the current child where material button is
child: Material(
        elevation: 5.0,
        // color: Colors.lightBlueAccent,
        color: colour,
        borderRadius: BorderRadius.circular(30.0),
        child: MaterialButton(
          onPressed: onPressed,
          minWidth: 200.0,
          height: 42.0,
          child: Text(
            title,  
          ),
        ),
      ),



Now let us use the RoundedButton at the top, if you hover on it, it will tell you that it require an onpress as what we initialized in its constructor


Let's fill the requirements for its constructor. 
Reminder, in the onPressed(), we use a different way of naming a route, just use your way of pushing the navigator. 

new RoundedButton(title: 'Log In', colour: Colors.lightBlueAccent, onPressed: (){
              Navigator.pushNamed(context, LoginScreen.id);
            },),


Now our Button is reusable!!!

You can now call the RoundedButton with your own specific application for it.



Creating its Own File

Inside your lib, creat a folder and name it  "components", inside it create a dart file    rounded_buttons.dart

Open the rounded_button.dart and import material.dart

import 'package:flutter/material.dart'


Go back to your previous dart file which in my case is welcome_screen.dart and cut the RoundedButton stateless widget and paste it in your file rounded_buttons.dart

The current rounded_buttons.dart contains the following code
import 'package:flutter/material.dart'



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


  RoundedButton({this.title,this.colour,@required this.onPressed});

  final Color colour;
  final String title;
  final Function onPressed; 

  @override
  Widget build(BuildContext context) {
    return Padding(
      padding: EdgeInsets.symmetric(vertical: 16.0),
      child: Material(
        elevation: 5.0,
        // color: Colors.lightBlueAccent,
        color: colour,
        borderRadius: BorderRadius.circular(30.0),
        child: MaterialButton(
          onPressed: onPressed,
          minWidth: 200.0,
          height: 42.0,
          child: Text(
            title,  
          ),
        ),
      ),
    );
  }
}


Now go back to welcome_screen.dart and import the new rounded_button.dart
import '../components/rounded_button.dart';



Now we have refactor our code :)















Flutter Hero Animation for beginners

Flutter Hero Animation for beginners




One of the basic animation in flutter is the Hero Animation. So what really is a Hero Animation?

Requirements:
1. You can already create a flutter project.
2. A sample flutter project that we can use in this tutorial.

"I assume in this tutorial that you already have knowledge to setup flutter project. Ready your project and we will start with a basic main.dart." :)

Let's use StatelessWidget since we don't need to change or save a state in our main.

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Container(
      
    );
  }
}


Creating a Screen


    Make a directory inside your lib, name it screens. Inside the screens create 2  screens, home.dart and login.dart.  We will set the home.dart as our homepage in the main.dart.




Main.dart
Let's prepare our main.dart. Make a scaffold and set the home in a class named login.dart

In our code above, change the return from Container to Materialapp() class. Add a property  home then make the value login(). It is the class of our login screen.


import 'package:flutter/material.dart';
import './screens/login.dart';

void main()=>runApp(MyApp());

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: Login(),
    );
  }
}


Our app will show a squiggly line on Login() because it can't find the class in current file. We need to to create the login class then import it in the main.dart. For now we can already add the import even if we haven't created the class as you can see  the line  import './screens/login.dart';

Login.dart

Import marteriall.dart and create a StatelessWidget class of login

import 'package:flutter/material.dart';
import './home.dart';

class Login extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(title: Text('Login Page'),leading: Container(
        child: Hero(
              tag: 'logo',
              child: Icon(
                  Icons.star,color:Colors.yellow,size: 30,
                )
              ),
      ),),
      body: Column(
      
        mainAxisAlignment: MainAxisAlignment.center,
        children: <Widget>[
       
          Center(
            child: RaisedButton(
              color: Colors.blueAccent,
              child: Text('Go to Home'),
              onPressed: (){
                Navigator.push(
                  context,
                  MaterialPageRoute(
                    builder: (context){
                      return Home();
                    }
                  ),
                );
              },
            ),
          )
        ],
      ),
    );
  }
}



Home.dart


import 'package:flutter/material.dart';
import 'package:hero/screens/login.dart';

class Home extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(title: Text('Home Page'),),
      body: Column(
      
        mainAxisAlignment: MainAxisAlignment.center,
        children: <Widget>[
          Center(
            child: Hero(
              tag: 'logo',
              child: Icon(
                  Icons.star,color:Colors.yellow,size: 250,
                )
              )
          ),
          RaisedButton(
            color: Colors.blueAccent,
            child: Text('Go to login'),
            onPressed: (){
              Navigator.push(
                context,
                MaterialPageRoute(
                  builder: (context){
                    return Login();
                  }
                ),
              );
            },
          )
        ],
      ),
    );
  }
}


Study

Hero(
  tag: 'logo',
  child: Icon(
    Icons.star,color:Colors.yellow,size: 30,
  )
),

As you can see how we use the Hero widget in login.dart, we put the icon widget inside the Hero Widget. The Hero widget basically needs 2 properties, tag and child.

The tag is the one that identifies the widget you want to be animated which is in this case is our Icon Star. The tag must be in both screen that will have transition, it must have the same tag. 

Difference between login.dart and home.dart

The difference between the two screen is that the Hero  widget of home.dart and its icon star is locted in the appbar while in the the login.dart's Hero is located in the body. This will help you easily notice the transition where the star becomes smaller and jumped to the appbar of the homepage


login.dart

appBar: AppBar(title: Text('Login Page'),leading: Container(
        child: Hero(
              tag: 'logo',
              child: Icon(
                  Icons.star,color:Colors.yellow,size: 30,
                )
              ),
      )


home.dart

body: Column(
      
        mainAxisAlignment: MainAxisAlignment.center,
        children: <Widget>[
          Center(
            child: Hero(
              tag: 'logo',
              child: Icon(
                  Icons.star,color:Colors.yellow,size: 250,
                )
              )
          ),
]
)