online software programming courses

Flutter mobile development tutorial for beginners with given code

This is flutter Mobile UI design tutorial, show you how to build a feed and about me pages step by step with animated navigation bar.

You learn how to use the basic widgets like Container, Expanded, Padding, Scaffold and build a pretty good looking mobile App.

Specially if you are a beginners, this is the best app tutorial for you.

You will learn how to use

1. How to Scaffold widget with Body and BottomNavigationBar

2. How to create scrollable column or widget using SingleChildScrollView

3. How to wrap Expand widget with SingleChildScrollView

4. How to create a card in flutter and make a map of them and iterate through it

5. How to create a custom bottom navigation bar and animate it

See the project stucture

If you use the same project structure for assets then you should update the pubspec.yaml file and write the correct images path. I have saved the assets in img folder. See the screen shot below

flutter pubspec.yaml.png

Code for my home page. Create a file called my_main_page.dart and copy the code in the file and put the file in your lib folder

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

import 'about.dart';
import 'feed.dart';
import 'feed_nav_bar.dart';

class MyHomePage extends StatefulWidget {
  @override
  _MyHomePageState createState() => _MyHomePageState();
}

class _MyHomePageState extends State<MyHomePage> {
  int _currentIndex = 0;
  final List<Widget> _children = [
    FeedPage(),
    About(),
  ];
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      backgroundColor: Colors.white,
      body: _children[_currentIndex],
      bottomNavigationBar: BottomNavyBar(

        selectedIndex: _currentIndex,
        onItemSelected: (index) {
          setState(() => _currentIndex = index);
        },
        items: <BottomNavyBarItem>[
          BottomNavyBarItem(
              icon:Container(
                //  padding: EdgeInsets.only(top:10),

                child: Icon(Icons.home),
              ),
              title:Container(
                // padding: EdgeInsets.only(top:10),
                child: Text('Feed'),
              )
          ),
          BottomNavyBarItem(
              title: Text('My'),
              icon: Icon(Icons.person)
          ),
          BottomNavyBarItem(
              title: Text('Chat'),
              icon: Icon(Icons.chat_bubble)
          ),

        ],
      ),
    );
  }
}


 

Code for person_detail_card. Create file called person_detail_card.dart and put the file in the lib folder

import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:flutter_app_feed/person_model.dart';
class PersonDetailCard extends StatelessWidget {
  final Person person;
  const PersonDetailCard({Key key, this.person}):super(key:key);
  @override
  Widget build(BuildContext context) {
    return Card(
      margin: person.name=="Bill Will"? EdgeInsets.only(top:10, bottom: 18, left:18, right: 18):
          EdgeInsets.only(top:0, bottom: 18, left: 18, right: 18),
      color: Colors.white,
      elevation: 50.0,
      shadowColor: Colors.grey.withOpacity(0.5),
      shape: RoundedRectangleBorder(
        borderRadius: BorderRadius.circular(15.0),

      ),
      child:  Padding(padding: const EdgeInsets.all(10.0),
        child: Row(
          children: [
            Container(
                  width: 80,
                  height: 80,
              padding: const EdgeInsets.only(right: 20),
              decoration: BoxDecoration(
                shape: BoxShape.circle,
                border: Border.all(width: 5, color:Colors.white),
                image: DecorationImage(
                  image:AssetImage(person.img),
                ),
                boxShadow: [
                  BoxShadow(
                    blurRadius: 7,
                    spreadRadius: 8,
                    color: Colors.grey,
                    offset: Offset(0, 3),
                  )
                ]
              ),
            ),
            SizedBox(width: 20,),
            Column(
              crossAxisAlignment: CrossAxisAlignment.start,
              children: [
                Padding(padding: const EdgeInsets.only(top:10, bottom: 8),
                child: Text(
                  person.name, style: TextStyle(fontSize: 24),
                ),

                ),
                Padding(padding: const EdgeInsets.only(top:0, bottom: 0),
                  child: Text(
                    person.job, style: TextStyle(fontSize: 20),
                  ),
                ),
                Padding(padding: const EdgeInsets.only(top:5, bottom: 8),
                  child: Row(
                    children: [
                      Icon(Icons.access_time_outlined),
                      SizedBox(width: 10,),
                      Text(person.clock, style: TextStyle(color: Colors.grey),)
                    ],
                  )
                ),
              ],
            ),
            Expanded(child: Row(
              children: [
                Expanded(child: Container()),
                Column(
                  children: [
                    Icon(Icons.circle, size:8),
                    SizedBox(height: 5,),
                    Icon(Icons.circle, size:8),
                    SizedBox(height: 5,),
                    Icon(Icons.circle, size:8),
                  ],
                )
              ],
            ))
          ],
        ),
        ),

    );
  }
}

 

Code for person_model file. Create a file called person_model.dart and copy the code in the file and put in the lib folder

Code for icon_dart file. Create a file called icon_container and copy the file in the code and put the file in the lib folder.

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

class IconContainer extends StatelessWidget {
  final Color bgColor;
  final double width, height;
  final Icon icon;
  final int index;
  final Color borderColor;
  final double size;
  final bool img;
  final String imgPath;
  const IconContainer({Key key,this.img,this.imgPath,this.size, this.borderColor=Colors.transparent, this.index, this.bgColor, this.width, this.height, this.icon}):super(key:key);
  @override
  Widget build(BuildContext context) {
    List<IconData> _icons = [
// The underscore declares a variable as private in dart.
      Icons.book,
      Icons.work,
      Icons.umbrella,
      Icons.add_location,
      Icons.medical_services,
      Icons.cast_for_education_outlined,
      Icons.construction,
      Icons.flight
    ];
    return Container(
     width: this.width,
      height: this.height,
      child: Icon(
        _icons[this.index], size:this.size, color:Colors.white
      ),
      decoration: BoxDecoration(
        color:this.bgColor,
        shape: BoxShape.circle,
        border: this.borderColor==Colors.transparent?
        Border.all(width: 5, color:Colors.transparent):
        Border.all(width: 5, color:this.borderColor)
          ,

      ),
    );
  }
}

 

Get the code for Feed page. Create a file called feed.art and copy the code and put in lib folder

import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:flutter_app_feed/person_detail_card.dart';
import 'package:flutter_app_feed/person_model.dart';

class FeedPage extends StatefulWidget {
  @override
  _FeedPageState createState() => _FeedPageState();
}

class _FeedPageState extends State<FeedPage> {
  List<Person> persons = [
    Person(
        name: 'Bill Will',
        img: 'img/pic-7.png',
        job: "Software Developer",
        clock: '3:40'),
    Person(
        name: 'Andy Smith',
        img: 'img/pic-2.png',
        job: "UI Designer",
        clock: '5:50'),
    Person(
        name: 'Julie Robert',
        img: 'img/pic-4.png',
        job: "Software Tester",
        clock: '9:20'),
    Person(
        name: 'Creepy Story',
        img: 'img/pic-5.png',
        job: "Software Tester",
        clock: '9:20'),
    Person(
        name: 'Cloe Suger',
        img: 'img/pic-6.png',
        job: "Software Tester",
        clock: '9:20'),
    Person(
        name: 'Colie Story',
        img: 'img/pic-1.png',
        job: "Software Tester",
        clock: '9:20')
  ];


  @override
  Widget build(BuildContext context) {
    return Column(
      children: [
        Container(
          color:Color(0xFFf7be7c),
          padding: const EdgeInsets.fromLTRB(18, 50, 18, 18),
          child: Row(
            mainAxisAlignment: MainAxisAlignment.spaceBetween,
            children: [
              Text("Feed", style: TextStyle(fontWeight: FontWeight.bold, fontSize: 30),),
              Icon(Icons.format_align_center_outlined, size:40),
            ],
          ),
        ),
        Expanded(child: SingleChildScrollView(
          child: Column(
            children: persons.map((p){
              return PersonDetailCard(person:p);
            }).toList()
          ),
        ))
      ],
    );
  }
}

 

Code for about.dart file. Create a file called about.dart and put the code in the lib folder

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

import 'icon_container.dart';
class About extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return
      Container(
        color:Color(0xFFfef9eb),
      child: Column(
      children: [
        Container(
          padding: const EdgeInsets.fromLTRB(18, 50, 18, 18),
          margin: const EdgeInsets.only(bottom: 20),
          child: Column(
            children: [
              Row(
            mainAxisAlignment: MainAxisAlignment.spaceBetween,
                children: [
                  Icon(Icons.search, size:30),
                  Icon(Icons.search, size:30)

                ],
              ),
              Row(
                mainAxisAlignment: MainAxisAlignment.spaceBetween,
                children: [
                  Container(
                    width: 80,
                    height: 80,
                    margin: const EdgeInsets.only(left: 30, right: 30),
                    decoration: BoxDecoration(
                      shape: BoxShape.circle,
                      image:DecorationImage(

                      image: AssetImage("img/pic-1.png"),
                      )

                    ),
                  ),
                  Padding(padding: const EdgeInsets.only(right: 30),

                  child: Column(
                    children: [
                      Text("Dastagir Ahmed", style: TextStyle(fontSize: 20),),
                      Text("App Developer", style: TextStyle(fontSize: 16, color:Colors.grey),)
                    ],
                  )
                  )

                ],
              ),


            ],
          ),
          decoration: BoxDecoration(
            borderRadius: BorderRadius.circular(50.0),
            color:Color(0xFFf7be7c),

          ),
        ),

        Expanded(
          child: SingleChildScrollView(
            child:Padding(
            padding: const EdgeInsets.only(left:18, right: 18),

            child: Column(
              children: [
                Row(

                mainAxisAlignment: MainAxisAlignment.spaceBetween,
                  children: [

                Text("My Tasks", style: TextStyle(fontSize: 30, color:Color(0xFF3c4e60))),
                IconContainer(index:0,width: 80, height: 80, size:30, bgColor: Colors.red, borderColor: Colors.transparent,),
                  ],
                ),
                SizedBox(height: 20,),
                Row(
                  mainAxisAlignment: MainAxisAlignment.start,
                  children: [
                    IconContainer(index:0,width: 80, height: 80, size:30, bgColor: Colors.red, borderColor: Colors.transparent,),
                    Text("My Tasks", style: TextStyle(fontSize: 30, color:Color(0xFF3c4e60))),
                  ],
                ),

                SizedBox(height: 20,),
                Row(
                  mainAxisAlignment: MainAxisAlignment.start,
                  children: [
                    IconContainer(index:0,width: 80, height: 80, size:30, bgColor: Colors.red, borderColor: Colors.transparent,),
                    Text("My Tasks", style: TextStyle(fontSize: 30, color:Color(0xFF3c4e60))),
                  ],
                ),  SizedBox(height: 20,),
                Row(
                  mainAxisAlignment: MainAxisAlignment.start,
                  children: [
                    IconContainer(index:0,width: 80, height: 80, size:30, bgColor: Colors.red, borderColor: Colors.transparent,),
                    SizedBox(width: 5,),
                    Column(
                      children: [

                    Text("My Tasks", style: TextStyle(fontSize: 30, color:Color(0xFF3c4e60))),
                    SizedBox(width: 5,),
                    Text("My Tasks", style: TextStyle(fontSize: 30, color:Color(0xFF3c4e60))),
                      ],
                    ),
                  ],
                ),
                Row(
                  children: [

               Text(

                 "Active Projects", style: TextStyle(fontSize: 24, color:Color(0xFF1a3048)),
               )
                  ],
                ),
                SizedBox(
                  height: 20,
                ),
                Row(
                  mainAxisAlignment: MainAxisAlignment.spaceBetween,
                  children: [
                    Container(
                        width: 180,
                        height: 250,

                        decoration: BoxDecoration(
                            borderRadius: BorderRadius.all(Radius.circular(40)),
                            color: Color(0xFF3d9398)
                        ),
                        child:Column(
                          children: [
                            Padding(padding: const EdgeInsets.only(left: 10, right: 10, top:50),
                              child: IconContainer(width: 80, height: 80, size:30, index:4, bgColor:Color(0xFF3d9398), borderColor: Colors.grey,),
                            ),
                            SizedBox(
                              height: 20,
                            ),
                            Text(
                              "Medical App",
                              style: TextStyle(fontSize: 22, fontWeight: FontWeight.bold, color:Colors.white),
                            ),
                            SizedBox(
                              height: 15,
                            ),
                            Text(
                              "They produce pills",
                              style: TextStyle(fontSize: 18, fontWeight: FontWeight.bold, color:Colors.grey[100]),
                            ),
                          ],
                        )

                    ),
                    //SizedBox(width: 25,),

                    Container(
                        width: 180,
                        height: 250,

                        decoration: BoxDecoration(
                            borderRadius: BorderRadius.all(Radius.circular(40)),
                            color: Color(0xFFe46471)
                        ),
                        child:Column(
                          children: [
                            Padding(padding: const EdgeInsets.only(left: 10, right: 10, top:50),
                              child: IconContainer(width: 80, height: 80, size:30, index:5, bgColor:Color(0xFFe46471), borderColor: Colors.grey,),
                            ),
                            SizedBox(
                              height: 20,
                            ),
                            Text(
                              "Teaching App",
                              style: TextStyle(fontSize: 22, fontWeight: FontWeight.bold, color:Colors.white),
                            ),
                            SizedBox(
                              height: 15,
                            ),
                            Text(
                              "They teach kids",
                              style: TextStyle(fontSize: 18, fontWeight: FontWeight.bold, color:Colors.grey[100]),
                            ),
                          ],
                        )

                    )


                  ],
                ),
                SizedBox(
                  height: 20,
                ),
                Row(
                  mainAxisAlignment: MainAxisAlignment.spaceBetween,
                  children: [
                    Container(
                        width: 180,
                        height: 250,

                        decoration: BoxDecoration(
                            borderRadius: BorderRadius.all(Radius.circular(40)),
                            color: Color(0xFFf7be7c)
                        ),
                        child:Column(
                          children: [
                            Padding(padding: const EdgeInsets.only(left: 10, right: 10, top:50),
                              child: IconContainer(width: 80, height: 80, size:30, index:4, bgColor:Color(0xFF3d9398), borderColor: Colors.grey,),
                            ),
                            SizedBox(
                              height: 20,
                            ),
                            Text(
                              "Medical App",
                              style: TextStyle(fontSize: 22, fontWeight: FontWeight.bold, color:Colors.white),
                            ),
                            SizedBox(
                              height: 15,
                            ),
                            Text(
                              "They produce pills",
                              style: TextStyle(fontSize: 18, fontWeight: FontWeight.bold, color:Colors.grey[100]),
                            ),
                          ],
                        )

                    ),
                    //SizedBox(width: 25,),

                    Container(
                        width: 180,
                        height: 250,

                        decoration: BoxDecoration(
                            borderRadius: BorderRadius.all(Radius.circular(40)),
                            color: Color(0xFF6688e4)
                        ),
                        child:Column(
                          children: [
                            Padding(padding: const EdgeInsets.only(left: 10, right: 10, top:50),
                              child: IconContainer(width: 80, height: 80, size:30, index:6, bgColor:Color(0xFF6688e4), borderColor: Colors.grey,),
                            ),
                            SizedBox(
                              height: 20,
                            ),
                            Text(
                              "Construciton App",
                              style: TextStyle(fontSize: 22, fontWeight: FontWeight.bold, color:Colors.white),
                            ),
                            SizedBox(
                              height: 15,
                            ),
                            Text(
                              "A big company",
                              style: TextStyle(fontSize: 18, fontWeight: FontWeight.bold, color:Colors.grey[100]),
                            ),
                          ],
                        )

                    )


                  ],
                )
              ],
            ),
    )
          ),
        )

      ],
    )
      );

  }
}

 

Get the code for the Bottom Navigation 

library bottom_navy_bar;

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

/// A beautiful and animated bottom navigation that paints a rounded shape
/// around its [items] to provide a wonderful look.
///
/// Update [selectedIndex] to change the selected item.
/// [selectedIndex] is required and must not be null.
class BottomNavyBar extends StatelessWidget {

  BottomNavyBar({
    Key key,
    this.selectedIndex = 0,
    this.showElevation = true,
    this.iconSize = 24,
    this.backgroundColor,
    this.itemCornerRadius = 50,
    this.containerHeight = 56,
    this.animationDuration = const Duration(milliseconds: 270),
    this.mainAxisAlignment = MainAxisAlignment.spaceBetween,
    this.items,
    this.onItemSelected,
    this.curve = Curves.linear,
  }) : assert(items.length >= 2 && items.length <= 5),
        super(key: key);

  /// The selected item is index. Changing this property will change and animate
  /// the item being selected. Defaults to zero.
  final int selectedIndex;

  /// The icon size of all items. Defaults to 24.
  final double iconSize;

  /// The background color of the navigation bar. It defaults to
  /// [Theme.bottomAppBarColor] if not provided.
  final Color backgroundColor;

  /// Whether this navigation bar should show a elevation. Defaults to true.
  final bool showElevation;

  /// Use this to change the item's animation duration. Defaults to 270ms.
  final Duration animationDuration;

  /// Defines the appearance of the buttons that are displayed in the bottom
  /// navigation bar. This should have at least two items and five at most.
  final List<BottomNavyBarItem> items;

  /// A callback that will be called when a item is pressed.
  final ValueChanged<int> onItemSelected;

  /// Defines the alignment of the items.
  /// Defaults to [MainAxisAlignment.spaceBetween].
  final MainAxisAlignment mainAxisAlignment;

  /// The [items] corner radius, if not set, it defaults to 50.
  final double itemCornerRadius;

  /// Defines the bottom navigation bar height. Defaults to 56.
  final double containerHeight;

  /// Used to configure the animation curve. Defaults to [Curves.linear].
  final Curve curve;

  @override
  Widget build(BuildContext context) {
    final bgColor = backgroundColor ?? Theme.of(context).bottomAppBarColor;

    return Container(
      decoration: BoxDecoration(
        color: bgColor,
        boxShadow: [

          const BoxShadow(
            color: Colors.black12,
            blurRadius: 2,
          ),
        ],
      ),
      child: SafeArea(
        child: Container(
          width: double.infinity,
          height: containerHeight,
          padding: const EdgeInsets.symmetric(vertical: 6, horizontal: 8),
          child: Row(
            mainAxisAlignment: mainAxisAlignment,
            children: items.map((item) {
              var index = items.indexOf(item);
              return GestureDetector(
                onTap: () => onItemSelected(index),
                child: _ItemWidget(
                  item: item,
                  iconSize: iconSize,
                  isSelected: index == selectedIndex,
                  backgroundColor: bgColor,
                  itemCornerRadius: itemCornerRadius,
                  animationDuration: animationDuration,
                  curve: curve,
                ),
              );
            }).toList(),
          ),
        ),
      ),
    );
  }
}

class _ItemWidget extends StatelessWidget {
  final double iconSize;
  final bool isSelected;
  final BottomNavyBarItem item;
  final Color backgroundColor;
  final double itemCornerRadius;
  final Duration animationDuration;
  final Curve curve;

  const _ItemWidget({
    Key key,
    this.item,
    this.isSelected,
    this.backgroundColor,
    this.animationDuration,
    this.itemCornerRadius,
    this.iconSize,
    this.curve = Curves.linear,
  })  : super(key: key);

  @override
  Widget build(BuildContext context) {
    return Semantics(
      container: true,
      selected: isSelected,
      child: AnimatedContainer(
        //I changed here
        width: isSelected ? 150 : 50,
        height: double.maxFinite,
        duration: animationDuration,
        curve: curve,
        decoration: BoxDecoration(
          color:
          isSelected ? item.activeColor.withOpacity(0.2) : backgroundColor,
          borderRadius: BorderRadius.circular(itemCornerRadius),
        ),
        child: SingleChildScrollView(
          scrollDirection: Axis.horizontal,
          physics: NeverScrollableScrollPhysics(),
          child: Container(
            width: isSelected ? 150 : 40,
            padding: EdgeInsets.symmetric(horizontal: 8),
            child: Row(
              mainAxisSize: MainAxisSize.max,
              mainAxisAlignment: MainAxisAlignment.center,
              crossAxisAlignment: CrossAxisAlignment.center,
              children: <Widget>[
                Expanded(child: Container(

                )),
                IconTheme(
                  data: IconThemeData(
                    size: iconSize,
                    color: isSelected
                        ? item.activeColor.withOpacity(1)
                        : item.inactiveColor == null
                        ? item.activeColor
                        : item.inactiveColor,
                  ),
                  child: item.icon,
                ),

                Expanded(
                  child: Container(
                    //margin: const EdgeInsets.only(right: 20),
                    // padding: const EdgeInsets.only(left:4, right: 4, bottom: 4, top:4),
                    child: DefaultTextStyle.merge(
                      style: TextStyle(
                        color: item.activeColor,
                        fontWeight: FontWeight.bold,
                      ),
                      maxLines: 1,
                      textAlign: item.textAlign,
                      child: item.title,
                    ),
                  ),
                ),
                Expanded(child: Container(

                )),

              ],
            ),
          ),
        ),
      ),
    );
  }
}

/// The [BottomNavyBar.items] definition.
class BottomNavyBarItem {

  BottomNavyBarItem({
    this.icon,
    this.title,
    this.activeColor = Colors.redAccent,
    this.textAlign,
    this.inactiveColor= Colors.amber,
  });

  /// Defines this item's icon which is placed in the right side of the [title].
  final Widget icon;

  /// Defines this item's title which placed in the left side of the [icon].
  final Widget title;

  /// The [icon] and [title] color defined when this item is selected. Defaults
  /// to [Colors.blue].
  final Color activeColor;

  /// The [icon] and [title] color defined when this item is not selected.
  final Color inactiveColor;

  /// The alignment for the [title].
  ///
  /// This will take effect only if [title] it a [Text] widget.
  final TextAlign textAlign;

}