Completed

Flutter Beginner

Jabatan Pendaftaran Negara (JPN)

Date
7 Aug 2021
Organised by
RH Dynamic Resources
Trainer
Azman Zakaria
Attendees
15

Kursus ini berkonsepkan From Zero to Hero . Peserta dianggap telah mempunyai asas dalam apa-apa jenis bahasa pengaturcaraan, tetapi pemula kepada Flutter / Dart. Peserta seharusnya telah mempunyai asas SQL yang baik untuk mendapat hasil sepenuhnya dari kursus ini. 

Tools yang akan digunakan didalam kelas ini adalah seperti berikut :-

  • Android Studio
  • Flutter 2
  • Dart 2.x
  • SQL Yog
  • Smart phone with data cable

Dicadangkan PC / notebook yang akan digunakan ialah menggunakan Window 10 dengan RAM minimal 8 Gb, dan kapasiti Storage yang Free sebanyak min 10 Gb

Syllabus

Introduction

Flutter – a simple and high-performance framework based on Dart language, provides high performance by rendering the UI directly in the operating system’s canvas rather than through a native framework. Flutter also offers many ready-to-use widgets (UI) to create a modern application. These widgets are optimized for the mobile environments and designing the application using widgets is as simple as designing HTML.

What you will learn

This course is for beginners to Flutter and assume students have some basic background of programming language knowledge (other than dart / flutter). This course will cover the following core topics:

  • Introduction to dart
  • Introduction to flutter
  • Development environment
  • Widgets
  • Widgets composition
  • Dart basic
  • Sample of real-world application development

Course Duration : 5 days

1.0 Introduction to the course

  1.1 what is flutter
  1.2 why flutter
  1.3 The Anatomy of a Flutter App
 

2.0 Installation

  2.1 Windows Setup Step 1 - Install the Flutter SDK
  2.2 Windows Setup Step 2 - Install Android Studio
  2.3 Windows Setup Step 3 - Install the Android Emulator
 

3.0 Creating a New Flutter Project from Scratch

  3.1 A quick note about Hot Reload
  3.2 Scaffolding a Flutter App
  3.3 Working with Assets in Flutter & the Pubspec file
  3.4 How to Add App Icons to the iOS and Android Apps
  3.5 Deploying Your Flutter Apps to a Physical Device
  3.6 Deploying Flutter Apps to an Android Phone
 

4.0 The I Am Poor Challenge

  4.1  The challenge
  4.2  Show Off Your Work!
 

5.0 MiCard - A Single Screen Personal Business Card App

  5.1  Hot Reload and Hot Restart - Flutter Power Tools
  5.2  How to Use Container Widgets
  5.3  How to use Column & Row Widgets for Layout
  5.4  Flutter Layouts Challenge
  5.5  Tapping into Widget Properties
  5.6  Incorporating Custom Fonts in Your Flutter App
  5.7  Adding Material Icons with the Icon Widget  
  5.8  Flutter Card & ListTile Widgets
 

6.0 Dicee - A Stateful Dice App

  6.1 Using the Expanded Widget to Create Flexible Layouts
  6.2 How to Use Intention Actions
  6.3 Adding Gesture Detection with Flutter Button Widges
  6.4 Making the Dice Image Change Reactively
  6.5 [Dart] Variables
  6.6 [Dart] Data Types
  6.7 Stateful vs. Stateless Widgets - What's the Difference?
  6.8 Randomising the Dice
 

7.0 Magic 8 Ball - A Decision Making App

  7.2 Step 1 - Set Up The Project
  7.2 Step 2 - Create a Stateless Widget
  7.3 Step 3 - Create a Stateful Widget
  7.4 Step 4 - Make it Interactive
  7.5 Step 5 - Randomise it
  7.6 Step 6 - Update the State
  7.7 Customise It!

8.0 Xylophone - A Simple Musical Instrument App

  8.1 What are Flutter & Dart Packages?
  8.2 How to Play Sound Across Platforms
  8.3 How to Play Multiple Sounds
  8.4 [Dart] Functions - Part 2
  8.5 Updating the UI of Our App
  8.6 [Dart] Functions - Part 3
  8.7 [Dart] Functions Challenge
  8.8 Refactoring Our App
  8.9 [Dart] Arrow Functions
  8.10 Customise It!
 

9.0 Building a Score Keeper

  9.1 [Dart] Lists
  9.2 Displaying the Questions
  9.3 Checking User Answers
  9.4 [Dart] Conditionals - IF/ELSE
  9.5 More Dart Programming Challenges
  9.6 Creating a Question Class
  9.7 [Dart] Classes and Objects
  9.8 Abstraction in Action
  9.9 Encapsulation in Action
  9.10Inheritance in Action
  9.11Polymorphism in Action
  9.12 Adding Back the Score Keeper
  9.13 Code Challenge
  9.14 [Dart] Class Constructors
 


 

Training Materials

flutter.dev

Official Flutter website

developer.android.com

Official Android Studio website

dart.dev

Official Dart Lang website

Source Code Project Flutter (MyIDN)

Source Code Project PHP (API)  (MyIDN)

Trainer Profile

 Nama : Azman bin Zakaria
 Umur : 52 tahun
 Pengalaman Dalam Bidang IT : 21 Tahun
 Syarikat : Favourite Trainer Sdn Bhd
 Kelulusan :

  • Bachelor IT UiTM
  • Diploma Computer Science UiTM
  • HRDF Certified Instructor

Azman merupakan senior programmer yang passionate dalam bidang pengaturcaraan komputer dari awal mulai beliau bekerja pada tahun 2000 sehingga hari ini. Beliau mempunyai pengalaman bekerja yang luas di agensi kerajaan, swasta dan sebagai freelancer.
Antara pengaturcaraan yang selalu digunakan adalah seperti :

  • PHP (sejak tahun 2000)
  • PHP dan Laravel Framework
  • PHP dan Yii Framework
  • Coldfusion
  • Java 
  • Java dan Spring Boot Framework
  • Javascript
  • jQuery
  • Vuejs
  • Angular
  • Flutter

 

Notes

1.1  What is Flutter

Flutter is Google's platform-independent technology for creating applications used on mobile, desktop, and web platforms. Flutter is a mobile app SDK, complete with a framework, widgets, and tools, that give developers an easy way to build and deploy visually attractive, fast mobile apps on both Android and iOS platforms.


1.2  Why flutter

Flutter has the advantages of native development and allows you to reuse most of the code among different platforms, which can reduce your budget costs considerably. Flutter enables smooth and easy cross-platform mobile app development.

  • Single code-base which can be deployed to Android and iOS
  • A framework that supports multiple devices with various screen size
  • A lot of widgets to support user interface (i.e Row, Column, Stack, Center, Padding)
  • Hot-reload which is fast for development
  • Have access to Flutter source code (open source)


1.3  The Anatomy of a Flutter App

A flutter app is a combination of widget upon widget, just like legos.

In this module, we will install Android Studio instead of Visual Studio Code (VSC). This is a personal preference and commitment to a single platform for development. If you are using VSC, sometime later you will still need Android Studio. For testing during development, we will use Android Emulator and not an iOS emulator. This is because, in order to run an iOS emulator, you need a mac book, while in this class we will use windows OS. The overall installation will need at least 10GB of hard disk space.

 

2.1 Windows Setup Step 1 - Install the Flutter SDK


The following steps will install Flutter SDK:

  • go to https://flutter.dev/docs/get-started/install and click on the Windows icon
  • Click the link to download and install Git for Windows
  • Download zip file Flutter for Windows, then unzip the file to c:\ directory i.e C:\flutter
  • Set windows env. variable (PATH), to point to C:\flutter\bin folder
  • Open terminal, type flutter --version, and then flutter doctor


 

2.2 Windows Setup Step 2 - Install Android Studio


Android Studio initially is used to develop Android apps using Java and later Kotlin. Now it supports Flutter on Dart development. The following steps will install Android Studio for Flutter and Dart:

  • Go to https://developer.android.com and click download Android Studio
  • Click the installer and follow the installation wizard
  • Run Android studio, and go to settings > plugins, and install Flutter and Dart plugin
  • After restart Android Studion, you will see create new Flutter project


2.3  Windows Setup Step 3 - Install the Android Emulator

The following steps will install Android Emulator :

  • Create a new Flutter project
  • Click Android Virtual Device Manager (AVD) icon, and create an emulator (i.e Nexus 6, API level 29)
  • Click the play button to run the  app

Note: the download of API will take some time depending on internet speed. For performance see also the hardware accelerator during AVD setup.

 

2.4  Android Studio Tour

Here will discuss some main features of Android Studio.

1. Dart Analysis Panel

This is used to show errors during compiling. Double click the error to highlight the specific line of code for the error.

2. Select Open File

This is to highlight the currently opened file

3. Expand / Collapse Code

This helps to unclutter the code and only focus on the working one.

4. Flutter Outline

This is used to view the tree structure of our codebase.

5. Flutter Inspector

This is used as an inspector just like in Google Chrome. It's is used to inspect components on emulators, and reflect them back on source code.

6. Console

This panel will show errors during runtime.
 

2.5   Flutter Project Structure

Android Folder 

This folder contains a complete Android native app project and is used when building your Flutter application for Android. In this case, the Flutter code is compiled and then injected into this Android project, so that the result is a native Android application. E.g. when we’re using the Android emulator as seen in the first part of the project, this Android project is used to build the Android application which is then deployed to the Android Virtual Device. In most cases, you do not need to edit anything in the android folder directly.
 

Build Folder

This folder is the holding the compiled code of your Flutter application. The content of this folder is automatically generated as part of the Flutter build process so that you don’t need to change anything manually inside this folder. If you’re working on a Mac you should be able to see the ios folder in your project structure as well. The folder contains a complete XCode iOS native project which is used when building your Flutter application for iOS. It’s used in the same way as the project which is contained in the android folder is used when building for Android.
 

Lib Folder

Inside this folder, you’ll find the Dart files which contain the code of your Flutter application. So this is the folder where you’d spend most of the time when implementing Flutter applications. By default, this folder is containing the file main.dart.
 

Test folder

This folder is containing code that is written for the Flutter application in order to perform automated tests when building.
 

.gitignore file

This is a text file containing a list of files, file extensions, and folders that should be ignored when working with Git. Git is a distributed version control system for tracking changes in source code during software development. The entries already included in this file by default should already provide you with a good preset of things that should be ignored and working with Git in your Flutter project so that you can leave everything as it is.
 

.metadata

This file is managed by Flutter automatically and is used to track the properties of the Flutter project. This file is only changed by Flutter and you do not need to edit the content manually at any time.
 

.packages file

This file contains automatically generated content by the Flutter SDK and is used to contain a list of dependencies for your Flutter project.
 

pubspec.yaml file

This is the project’s configuration file you’ll use a lot when working with your Flutter project. This file contains:

  • General project settings like name, description, and version of the project
  • Project dependencies
  • Assets (e.g. images) which should be available in your Flutter application E.g. when adding new dependencies (Flutter Packages) to the project this file will be used to add the name of the package in the dependencies section and then the Flutter SDK will take care of downloading and adding this package afterward.

 

 

 

Let's create our first app...

3.1 Creating a new Flutter Project From Scratch


In this module, we will build a simple app called I am rich as in the following picture.

3.2 Scaffolding a Flutter App


in lib\main.dart remove everything and replace it with the following code.

import 'package:flutter/material.dart';

void main() {
  runApp(const MaterialApp(
    home: Center(
      child: Text('Hello'),
    ),
  ));
}

Try the following code to introduce Scaffold and AppBar. 

Adjust the first code to show an image on center screen / scaffold

import 'package:flutter/material.dart';

void main() {
  runApp(MaterialApp(
    home: Scaffold(
      appBar: AppBar(
        title: const Text('Am I Rich'),
        backgroundColor: Colors.blueGrey[900],
      ),
      body: const Center(
        child: Image(
          image: NetworkImage(
              'https://www.wanderingowl.com/wp-content/uploads/2020/09/blog_images_aurora_sunset_love.jpg'),
        ),
      ),
    ),
  ));
}

 

3.3 Working with Assets in Flutter & the Pubspec file


In this section, we will work on local images. The setting of the images is set in pubspec.yaml. YAML = YAML Aint Markup Language.

Every Flutter project includes a pubspec.yaml file is often referred to as the pubspec. A basic pubspec is generated when you create a new Flutter project. It’s located at the top of the project tree and contains metadata about the project that the Dart and Flutter tooling need to know. The pubspec is written in YAML, which is human readable, but be aware that white space (tabs spaces) matters.

Example of pubspec

name: i_am_rich
description: A new Flutter project.
publish_to: 'none' # Remove this line if you wish to publish to pub.dev
version: 1.0.0+1

environment:
  sdk: ">=2.12.0 <3.0.0"

dependencies:
  flutter:
    sdk: flutter
  cupertino_icons: ^1.0.2

dev_dependencies:
  flutter_test:
    sdk: flutter
  flutter_lints: ^1.0.0

flutter:
  uses-material-design: true
  assets:
    - images/diamond.png

Resource: diamond (click here to download the picture)

Update the code as in the following code:

import 'package:flutter/material.dart';

void main() {
  runApp(MaterialApp(
    home: Scaffold(
      appBar: AppBar(
        title: const Text('Am I Rich'),
        backgroundColor: Colors.blueGrey[900],
      ),
      body: const Center(
        child: Image(
          image: AssetImage('images/diamond.png'),
        ),
      ),
    ),
  ));
}

 

3.4  How to Add App Icon


When we upload to Google Play, we don't want to use the default icon right? Here is how we change the icon:

  • Resource: diamond icon (click here to download the picture)
  • Go to appicon.co, then drag and drop the image into the place holder there
  • Download and extract the zip file generated
  • Go to android/app/src/main/res folder, locate all mipmap-* folders and replace them with the folders from the extracted zip file.
  • Stop the Android emulator and then run again. The icon should be replaced with a new one.

 

3.6 Deploying Your Flutter Apps to a Physical Device


The next lessons will show you how to run your Flutter apps on to a physical device. Remember that in order to run your apps on an iPhone, you will need to have a Mac and have gone through all the setup steps in module 2.
 

3.7 Deploying Flutter Apps to an Android Phone


Here are the steps to connect to your phone:

  • Enable Developer Mode. This is normally under phone setting > about. Tap 7 times no active it.
  • Enable also USB debugging
  • Plug your phone into a notebook / PC using a USB cable. Make sure the cable support power and data.
  • Trust the USB debugging on your phone during dialog box pop-up.
  • In Android Studio now you will see your phone detected.
  • Choose the phone and click run

4.1  The challenge

Using what you have learnt from the I Am Rich app, you'll be building a simple Flutter app from scratch. Below is the Widget tree structure:

  • Using the Widget tree structure, create an app called I Am Poor, using everything you have learnt so far. Try to customise the app as much as you can to make it your own!
  • You can use your own images, or simply find one from the internet.


4.2  Show off your work!

I hope you enjoyed that challenge and you're now familiar with the basics of building Flutter apps. I really encourage you to take the opportunity and fully customize the design of your app. Once you're done and proud of it, post an image or gif of it in the Q&A section so I can personally congratulate you on your work!

In this module, we will learn how to create Mi Card - A single screen personal Biz Card App.

 

5.1   Hot Reload and Hot Restart - Flutter Power Tools

When we build any dart application it takes time to execute for the first time. So to resolve this problem we have two features in a flutter, namely Hot Reload and Hot restart which helps to decrease the execution time of our app once we execute it.  These two features help to decrease the execution time. They are far better and faster than the default restart.  It is important to note that it can only be used if you have executed your program once.

Hot Reload
A hot reload is a great functionality present in a flutter. It is the easiest and the fastest function which helps you to apply changes, fix bugs, creating UIs, and add features. It takes approximately one second to perform its functionality. In hot reload it does not destroy the preserved state.  But you cannot use a hot reload once the app gets killed. Please note, this feature only works for Steless Widget.

Perform Hot Reload:

  • Run your flutter editor from the app or using the command prompt. We can use hot reload in flutter debug mode.
  • Once your flutter project has been created do some changes in your code and perform a hot reload.
  • In windows, you can perform a hot reload using ‘ctrl+\’ or using the hot reload button. In mac devices, you perform hot reload using ‘cmd+s’. If you are working in the command prompt using flutter run enter ‘r’ to run.

Hot Restart
A hot restart has a slightly different functionality as compared to a hot reload. It is faster as compared to the full restart function. It destroys the preserved states of our app, and the code gets fully compiled again and starts from the default state. It takes more time as compared to hot reload but takes less time than the full restart function.

Perform Hot Restart:

  • Run your flutter editor from the app or using the command prompt.
  • Once your flutter project has been created do some changes in your code and perform a hot restart.
  • You can perform a hot restart using the hot reload button or pressing ctrl+shift+\.

Try the following code:

import 'package:flutter/material.dart';

void main() {
  runApp(MaterialApp(
    home: Scaffold(
      backgroundColor: Colors.teal,
      body: Container(),
    ),
  ));
}

and later update to this. See the different when to use hot reload and hot restart.

import 'package:flutter/material.dart';

void main() {
  runApp(MyApp());
}

class MyApp extends StatelessWidget {
  const MyApp({Key? key}) : super(key: key);

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: Scaffold(
        backgroundColor: Colors.teal,
        body: Container(),
      ),
    );
  }
}


5.2   How to Use Container Widgets

Container behaves like DIV in HTML.

  • Container with no children trying to be as big as possible
  • Container with children size to the children
  • Use SafeArea for container go under the nozzle of a phone
  • It's a single child layout

Main Container properties

  • width
  • height
  • margin. eg margin:EdgeInsets.symmetric(vertical:50, horizontal: 10))
  • padding
  • Color

5.3   How to use Column & Row Widgets for Layout

Try the following code for Colum widget:

import 'package:flutter/material.dart';

void main() {
  runApp(MyApp());
}

class MyApp extends StatelessWidget {
  const MyApp({Key? key}) : super(key: key);

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: Scaffold(
          appBar: AppBar(
            backgroundColor: Colors.blue,
            title: Text('My Demo'),
          ),
          backgroundColor: Colors.teal,
          body: Column(
            children: [
              Container(
                width: 100,
                height: 100,
                child: Text('Container 1'),
                color: Colors.white,
              ),
              Container(
                width: 100,
                height: 100,
                child: Text('Container 2'),
                color: Colors.blue,
              ),
              Container(
                width: 100,
                height: 100,
                child: Text('Container 2'),
                color: Colors.red,
              )
            ],
          )),
    );
  }
}

And then the following code for Row widget:

import 'package:flutter/material.dart';

void main() {
  runApp(MyApp());
}

class MyApp extends StatelessWidget {
  const MyApp({Key? key}) : super(key: key);

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: Scaffold(
          appBar: AppBar(
            backgroundColor: Colors.blue,
            title: Text('My Demo'),
          ),
          backgroundColor: Colors.teal,
          body: Row(
            children: [
              Container(
                width: 100,
                height: 100,
                child: Text('Container 1'),
                color: Colors.white,
              ),
              Container(
                width: 100,
                height: 100,
                child: Text('Container 2'),
                color: Colors.blue,
              ),
              Container(
                width: 100,
                height: 100,
                child: Text('Container 2'),
                color: Colors.red,
              )
            ],
          )),
    );
  }
}

 

5.4   Flutter Layouts Challenge

Now that you have learnt about Column and Row Widgets and how to use them to layout your app, it's time to test your understanding. The below image is a layout that I would like you to try and replicate with code. I recommend using the existing Mi Card app to create this layout and once you've achieved the desired look and you're satisfied with the solution then you can delete the challenge code from the project.

5.5   Tapping into Widget Properties

  • Create an image folder on root project, and get a person image into it
  • Change the pubpec.yaml, and click "get" button
  • Try the following code
name: micard
description: Digital Biz Card
publish_to: 'none' # Remove this line if you wish to publish to pub.dev
version: 1.0.0+1

environment:
  sdk: ">=2.12.0 <3.0.0"

dependencies:
  flutter:
    sdk: flutter
  cupertino_icons: ^1.0.2

dev_dependencies:
  flutter_test:
    sdk: flutter
  flutter_lints: ^1.0.0

flutter:
  uses-material-design: true
  assets:
    - images/azman.png
import 'package:flutter/material.dart';

void main() {
  runApp(MyApp());
}

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: Scaffold(
        backgroundColor: Colors.teal,
        body: SafeArea(
          child: Column(
            children: [
              CircleAvatar(
                radius: 50.0,
                backgroundImage: AssetImage('images/azman.png'),
              ),
              Text(
                'Azman Zakaria',
                style: TextStyle(
                  fontSize: 40.0,
                  color: Colors.white,
                ),
              )
            ],
          ),
        ),
      ),
    );
  }
}

5.6   Incorporating Custom Fonts in Your Flutter App

  • create font folder
  • download a font from fonts.google.com. search for Pacifico
  • Adjust pubspec.yaml
  • tru the following code
name: micard
description: Digital Biz Card
publish_to: 'none' # Remove this line if you wish to publish to pub.dev
version: 1.0.0+1

environment:
  sdk: ">=2.12.0 <3.0.0"

dependencies:
  flutter:
    sdk: flutter
  cupertino_icons: ^1.0.2

dev_dependencies:
  flutter_test:
    sdk: flutter
  flutter_lints: ^1.0.0

flutter:
  uses-material-design: true
  assets:
    - images/azman.png

  fonts:
  - family: Pacifico
    fonts:
    - asset: fonts/Pacifico-Regular.ttf

  - family: Source Sans Pro
    fonts:
    - asset: fonts/SourceSansPro-Regular.ttf
import 'package:flutter/material.dart';

void main() {
  runApp(MyApp());
}

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: Scaffold(
        backgroundColor: Colors.teal,
        body: SafeArea(
          child: Column(
            children: <Widget>[
              CircleAvatar(
                radius: 50.0,
                backgroundImage: AssetImage('images/azman.png'),
              ),
              Text(
                'Azman Zakaria',
                style: TextStyle(
                    fontSize: 40.0,
                    color: Colors.white,
                    fontFamily: 'Pacifico'),
              ),
              Text(
                'MOBILE DEVELOPER',
                style: TextStyle(
                    fontFamily: 'Source Sans Pro',
                    fontSize: 20,
                    letterSpacing: 2.5,
                    color: Colors.teal.shade100,
                    fontWeight: FontWeight.bold),
              )
            ],
          ),
        ),
      ),
    );
  }
}

5.7   Adding Material Icons with the Icon Widget

  • search for material.io website
  • try the following code
import 'package:flutter/material.dart';

void main() {
  runApp(MyApp());
}

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: Scaffold(
        backgroundColor: Colors.teal,
        body: SafeArea(
          child: Column(
            children: <Widget>[
              CircleAvatar(
                radius: 50.0,
                backgroundImage: AssetImage('images/azman.png'),
              ),
              Text(
                'Azman Zakaria',
                style: TextStyle(
                    fontSize: 40.0,
                    color: Colors.white,
                    fontFamily: 'Pacifico'),
              ),
              Text(
                'MOBILE DEVELOPER',
                style: TextStyle(
                    fontFamily: 'Source Sans Pro',
                    fontSize: 20,
                    letterSpacing: 2.5,
                    color: Colors.teal.shade100,
                    fontWeight: FontWeight.bold),
              ),
              Container(
                color: Colors.white,
                margin: EdgeInsets.symmetric(vertical: 10, horizontal: 25),
                padding: EdgeInsets.all(10),
                child: Row(
                  children: <Widget>[
                    Icon(
                      Icons.phone,
                      color: Colors.teal,
                    ),
                    SizedBox(width: 10.0),
                    Text(
                      '016 2370 394',
                      style: TextStyle(
                          fontSize: 20.0,
                          fontFamily: 'Source Sans Pro',
                          color: Colors.teal.shade900),
                    )
                  ],
                ),
              ),
              Container(
                color: Colors.white,
                margin: EdgeInsets.symmetric(vertical: 10, horizontal: 25),
                padding: EdgeInsets.all(10),
                child: Row(
                  children: <Widget>[
                    Icon(
                      Icons.email,
                      color: Colors.teal,
                    ),
                    SizedBox(width: 10.0),
                    Text(
                      'azman@favouritetrainer.com',
                      style: TextStyle(
                          fontSize: 20.0,
                          fontFamily: 'Source Sans Pro',
                          color: Colors.teal.shade900),
                    )
                  ],
                ),
              )
            ],
          ),
        ),
      ),
    );
  }
}

5.8   Flutter Card & ListTile Widgets

To finish it up, we will do the following:

  • Add Card to replace Container
  • Wrap Row with Padding
import 'package:flutter/material.dart';

void main() {
  runApp(MyApp());
}

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: Scaffold(
        backgroundColor: Colors.teal,
        body: SafeArea(
          child: Column(
            children: <Widget>[
              CircleAvatar(
                radius: 50.0,
                backgroundImage: AssetImage('images/azman.png'),
              ),
              Text(
                'Azman Zakaria',
                style: TextStyle(
                    fontSize: 40.0,
                    color: Colors.white,
                    fontFamily: 'Pacifico'),
              ),
              Text(
                'MOBILE DEVELOPER',
                style: TextStyle(
                    fontFamily: 'Source Sans Pro',
                    fontSize: 20,
                    letterSpacing: 2.5,
                    color: Colors.teal.shade100,
                    fontWeight: FontWeight.bold),
              ),
              Card(
                color: Colors.white,
                margin: EdgeInsets.symmetric(vertical: 10, horizontal: 25),
                child: Padding(
                  padding: EdgeInsets.all(20),
                  child: Row(
                    children: <Widget>[
                      Icon(
                        Icons.phone,
                        color: Colors.teal,
                      ),
                      SizedBox(width: 10.0),
                      Text(
                        '016 2370 394',
                        style: TextStyle(
                            fontSize: 20.0,
                            fontFamily: 'Source Sans Pro',
                            color: Colors.teal.shade900),
                      )
                    ],
                  ),
                ),
              ),
              Card(
                color: Colors.white,
                margin: EdgeInsets.symmetric(vertical: 10, horizontal: 25),
                child: Padding(
                  padding: EdgeInsets.all(20),
                  child: Row(
                    children: <Widget>[
                      Icon(
                        Icons.email,
                        color: Colors.teal,
                      ),
                      SizedBox(width: 10.0),
                      Text(
                        'azman@favouritetrainer.com',
                        style: TextStyle(
                            fontSize: 20.0,
                            fontFamily: 'Source Sans Pro',
                            color: Colors.teal.shade900),
                      )
                    ],
                  ),
                ),
              )
            ],
          ),
        ),
      ),
    );
  }
}

The Final output is like in the following image:

 

6.1 Using the Expanded Widget to Create Flexible Layouts

What we will create:

Steps:

  • create an image folder
  • download the following image and put them into the new folder. dice, dice1, dice2, dice3, dice4, dice5, dice6
  • Adjust pubspec.yaml accordingly
  • Try the following code
import 'package:flutter/material.dart';

void main() {
  runApp(const DicePage());
}

class DicePage extends StatelessWidget {
  const DicePage({Key? key}) : super(key: key);

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: Scaffold(
        backgroundColor: Colors.red,
        appBar: AppBar(
          title: Text('Dicee'),
          backgroundColor: Colors.red,
        ),
        body: Container(
          child: Row(
            children: [
              Expanded(child: Image.asset('image/dice1.png')),
              Expanded(
                child: Image.asset('image/dice2.png'),
              )
            ],
          ),
        ),
      ),
    );
  }
}

6.2 How to Use Intention Actions

Use Flutter Outline as in the following picture to add:

  • Center widget around Row widget
  • Padding around Image widget

body: Center(
          child: Row(
            children: [
              Expanded(
                  child: Padding(
                padding: const EdgeInsets.all(8.0),
                child: Image.asset('image/dice1.png'),
              )),
              Expanded(
                child: Padding(
                  padding: const EdgeInsets.all(8.0),
                  child: Image.asset('image/dice2.png'),
                ),
              )
            ],
          ),
        ),

6.3 Adding Gesture Detection with Flutter Button Widget

  • Remove the Padding widget as the button already have padding
  • add onPressec action to the button
import 'package:flutter/material.dart';

void main() {
  runApp(const DicePage());
}

class DicePage extends StatelessWidget {
  const DicePage({Key? key}) : super(key: key);

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: Scaffold(
        backgroundColor: Colors.red,
        appBar: AppBar(
          title: Text('Dicee'),
          backgroundColor: Colors.red,
        ),
        body: Center(
          child: Row(
            children: [
              Expanded(
                child: FlatButton(
                  onPressed: () {
                    print('Hello');
                  },
                  child: Image.asset('image/dice1.png'),
                ),
              ),
              Expanded(
                child: FlatButton(
                  onPressed: () {},
                  child: Image.asset('image/dice2.png'),
                ),
              )
            ],
          ),
        ),
      ),
    );
  }
}

6.4 Making the Dice Image Change Reactively

let's make the dice a bit dynamic

Widget build(BuildContext context) {
    var leftDice = 4;
    var rightDice = 2;
    return MaterialApp(
      home: Scaffold(
        backgroundColor: Colors.red,
        appBar: AppBar(
          title: Text('Dicee'),
          backgroundColor: Colors.red,
        ),
        body: Center(
          child: Row(
            children: [
              Expanded(
                child: FlatButton(
                  onPressed: () {
                    print('Hello');
                  },
                  child: Image.asset('image/dice$leftDice.png'),
                ),
              ),
              Expanded(
                child: FlatButton(
                  onPressed: () {},
                  child: Image.asset('image/dice$rightDice.png'),
                ),
              )
            ],
          ),
        ),
      ),
    );
  }

6.5 [Dart] Variables

A variable is “a named space in the memory” that stores values. In other words, it acts a container for values in a program. Variable names are called identifiers. Following are the naming rules for an identifier −

  • Identifiers cannot be keywords.
  • Identifiers can contain alphabets and numbers.
  • Identifiers cannot contain spaces and special characters, except the underscore (_) and the dollar ($) sign.
  • Variable names cannot begin with a number.

Type Syntax
A variable must be declared before it is used. Dart uses the var keyword to achieve the same. The syntax for declaring a variable is as given below −
var name = 'Smith';

All variables in dart store a reference to the value rather than containing the value. The variable called name contains a reference to a String object with a value of “Smith”. Dart supports type-checking by prefixing the variable name with the data type. Type-checking ensures that a variable holds only data specific to a data type. The syntax for the same is given below −

String name = 'Smith'; 
int num = 10;

 

6.6 [Dart] Data Types

Dart supports the following data types:

Data Type Keyword Description
Number int, double, num Numbers in Dart are used to represent numeric literals
Strings String Strings represent a sequence of characters
Booleans bool It represents Boolean values true and false
Lists List It is an ordered group of objects
Maps Map It represents a set of values as key-value pairs

 

6.7 Stateful vs. Stateless Widgets - What's the Difference?

A stateless widget never changes. Icon, IconButton, and Text are examples of stateless widgets. Stateless widgets subclass StatelessWidget. In simple words, Stateless widgets cannot change their state during the runtime of the app, which means the widgets cannot be redrawn while the app is in action. In Stateless widget, The “build” method can be called only ONCE while the app is in action, which is responsible for drawing the widgets onto the device screen. Example as follows.

class GreenFrog extends StatelessWidget {
  const GreenFrog({ Key? key }) : super(key: key);

  @override
  Widget build(BuildContext context) {
    return Container(color: const Color(0xFF2DBD3A));
  }
}

A stateful widget is dynamic: for example, it can change its appearance in response to events triggered by user interactions or when it receives data. They are the widgets that can change their state multiple times and can be redrawn onto the screen any number of times while the app is in action. example as follows.

class YellowBird extends StatefulWidget {
  const YellowBird({ Key key }) : super(key: key);

  @override
  _YellowBirdState createState() => _YellowBirdState();
}

class _YellowBirdState extends State<YellowBird> {
  @override
  Widget build(BuildContext context) {
    return Container(color: const Color(0xFFFFE306));
  }
}

6.8 Randomising the Dice

  • import the math library
  • call the Random().nextInt(6)
import 'package:flutter/material.dart';
import 'dart:math';

void main() {
  runApp(const DicePage());
}

class DicePage extends StatefulWidget {
  const DicePage({Key? key}) : super(key: key);

  @override
  _DicePageState createState() => _DicePageState();
}

class _DicePageState extends State<DicePage> {
  int leftDice = 4;
  int rightDice = 2;

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: Scaffold(
        backgroundColor: Colors.red,
        appBar: AppBar(
          title: Text('Dicee'),
          backgroundColor: Colors.red,
        ),
        body: Center(
          child: Row(
            children: [
              Expanded(
                child: FlatButton(
                  onPressed: () {
                    setState(() {
                      leftDice = Random().nextInt(6) + 1;
                    });
                  },
                  child: Image.asset('image/dice$leftDice.png'),
                ),
              ),
              Expanded(
                child: FlatButton(
                  onPressed: () {
                    setState(() {
                      rightDice = Random().nextInt(6) + 1;
                    });
                  },
                  child: Image.asset('image/dice$rightDice.png'),
                ),
              )
            ],
          ),
        ),
      ),
    );
  }
}

 

 

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

void main() {
  runApp(MyApp());
}

class MyApp extends StatefulWidget {
  const MyApp({Key? key}) : super(key: key);

  @override
  _MyAppState createState() => _MyAppState();
}

class _MyAppState extends State<MyApp> {
  // data / state
  int leftDice = 2;
  int rightDice = 3;

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: Scaffold(
        backgroundColor: Colors.red,
        appBar: AppBar(
          title: Text('Dicee'),
          backgroundColor: Colors.red,
        ),
        body: Center(
          child: Row(
            children: [
              Expanded(
                child: Padding(
                  padding: const EdgeInsets.all(8.0),
                  child: FlatButton(
                    onPressed: () {
                      // anonymous function. setState = redraw / refresh ui semula
                      randomize();
                    },
                    child: Image(
                      image: AssetImage('images/dice$leftDice.png'),
                    ),
                  ),
                ),
              ),
              Expanded(
                child: Padding(
                  padding: const EdgeInsets.all(8.0),
                  child: FlatButton(
                    onPressed: () {
                      randomize();
                    },
                    child: Image(
                      image: AssetImage('images/dice$rightDice.png'),
                    ),
                  ),
                ),
              ),
            ],
          ),
        ),
      ),
    );
  }

  void randomize() {
    setState(() {
      leftDice = Random().nextInt(6) + 1; // 1 - 6
      rightDice = Random().nextInt(6) + 1;
      print('leftDice = $leftDice');
    });
  }
}

 

8.1 What are Flutter & Dart Packages?

A package is a namespace that contains a group of similar types of classes, interfaces, and sub-packages. In Flutter, Dart organizes and shares a set of functionality through a package. Flutter always supports shared packages, which are contributed by other developers to the Flutter and Dart ecosystem. It's open-source that other people can use.

  • in this module, we will create a musical app. The app will look like this.
  • We will learn to use the flutter package to play sound
  • Head to pub.dev to view and search all the packages of Dart and Flutter available.
  • Create a new project titled "xylophone"
  • Create a directory called "assets", and put the following .wav file into it. download here
  • Adjust pubspec.yaml accordingly


8.2 How to Play Sound Across Platforms      

  • Head to pub.dev
  • Search for audioplayers
  • Install on current app by using pubspec.yaml, under dependencies section

 

8.3 How to Play Multiple Sounds

  • Try the following code to play note1.wav to note7.wav.
  • Next, try to add seven buttons to play seven different sounds. The result should be like the following picture:

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

void main() {
  runApp(
    MaterialApp(
      home: Scaffold(
        backgroundColor: Colors.teal,
        body: Center(
          child: TextButton(
            child: Text('Click Me'),
            style: ButtonStyle(
                backgroundColor: MaterialStateProperty.all(Colors.red)),
            onPressed: () async {
              final player = AudioCache();
              AudioPlayer result = await player.play('note1.wav',
                  mode: PlayerMode.LOW_LATENCY, volume: 5);
            },
          ),
        ),
      ),
    ),
  );
}


8.4 [Dart] Functions - Part 2

Functions are the building blocks of readable, maintainable, and reusable code. A function is a set of statements to perform a specific task. Functions organize the program into logical blocks of code. Once defined, functions may be called to access code. This makes the code reusable. Moreover, functions make it easy to read and maintain the program’s code.

A function declaration tells the compiler about a function's name, return type, and parameters. A function definition provides the actual body of the function.

void main() { 
   print(factorial(6));
}  

factorial(number) { 
   if (number <= 0) {         
      // termination case 
      return 1; 
   } else { 
      return (number * factorial(number - 1));    
      // function invokes itself 
   } 
}   

 


8.5 [Dart] Functions Challenge

Create a function to add two int numbers called add(int a, int b), and return an integer number. Call the function two times, and print the result to the console.


8.6 Refactoring Our App

This is the final code after refactoring

import 'package:flutter/material.dart';
import 'package:audioplayers/audioplayers.dart';
//import 'package:audioplayers/audio_cache.dart';

void mainx() {
  runApp(MusicPage());
}

class MusicPage extends StatelessWidget {
  const MusicPage({Key? key}) : super(key: key);

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: SafeArea(child: Music()),
    );
  }
}

class Music extends StatefulWidget {
  const Music({Key? key}) : super(key: key);

  @override
  _MusicState createState() => _MusicState();
}

class _MusicState extends State<Music> {
  @override
  void initState() {
    super.initState();
    final player = AudioCache();
    player.loadAll([
      'note1.wav',
      'note2.wav',
      'note3.wav',
      'note4.wav',
      'note5.wav',
      'note6.wav',
      'note7.wav'
    ]);
  }

  @override
  Widget build(BuildContext context) {
    return Column(
        crossAxisAlignment: CrossAxisAlignment.stretch,
        children: <Widget>[
          getButton(Colors.red, 1),
          getButton(Colors.yellow, 2),
          getButton(Colors.blue, 3),
          getButton(Colors.green, 4),
          getButton(Colors.teal, 5),
          getButton(Colors.amber, 6),
          getButton(Colors.pink, 7),
        ]);
  }

  Expanded getButton(Color color, int no) {
    return Expanded(
      child: TextButton(
        style: ButtonStyle(backgroundColor: MaterialStateProperty.all(color)),
        onPressed: () {
          //print(no);
          play(no);
        },
        child: Text(
          'Click Me',
          style: TextStyle(color: Colors.black),
        ),
      ),
    );
  }

  void play(int no) async {
    final player = AudioCache();
    AudioPlayer result = await player.play('note$no.wav',
        mode: PlayerMode.LOW_LATENCY, volume: 5);
    //print(result);
  }
}


8.9 [Dart] Arrow Functions

bool hasEmpty = aListOfStrings.any((s) => s.isEmpty);

// is equivalent to:
bool hasEmpty = aListOfStrings.any((s) {
  return s.isEmpty;
});

 

 

 

9.1 Introduction

in this app, we will create an app as in the following picture:

   

Download the following images for background:

 

9.2 Getting Data Location Across Platform

  • head to pub.dev, search for "geolocation"
  • copy the dependencies, and put it into pubspec.yaml
import 'package:flutter/material.dart';
import 'package:geolocator/geolocator.dart';

class LoadingScreen extends StatefulWidget {
  const LoadingScreen({Key? key}) : super(key: key);

  @override
  _LoadingScreenState createState() => _LoadingScreenState();
}

class _LoadingScreenState extends State<LoadingScreen> {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: Scaffold(
        body: Center(
          child: TextButton(child: Text('Get Location'), onPressed: () {
            getLocation();
          },),
        ),
      ),
    );
  }

  void getLocation() async {
    print('getting location ...');
    Position position = await Geolocator.getCurrentPosition(desiredAccuracy: LocationAccuracy.low);
    print(position);
  }
}
dependencies:
  flutter:
    sdk: flutter

  cupertino_icons: ^1.0.2
  geolocator: ^7.6.0

dev_dependencies:
  flutter_test:
    sdk: flutter

9.3 Future, Async, Await

Asynchronous operations let your program complete work while waiting for another operation to finish. Here are some common asynchronous operations:

  • Fetching data over a network.
  • Writing to a database.
  • Reading data from a file.
Future<String> createOrderMessage() async {
  var order = await fetchUserOrder();
  return 'Your order is: $order';
}

Future<String> fetchUserOrder() =>
    // Imagine that this function is
    // more complex and slow.
    Future.delayed(
      const Duration(seconds: 2),
      () => 'Large Latte',
    );

Future<void> main() async {
  print('Fetching user order...');
  print(await createOrderMessage());
}

To perform asynchronous operations in Dart, you can use the Future class and the async and await keywords.

import 'dart:io';

// async vs sync
void main() {
  task1();
  task2();
  task3();
}

void task1() {
  print('task 1');
}

Future<void> task2() async {
  Duration duration = Duration(seconds: 3);
  //sleep(duration); // simulate task yg loading lama
  await Future.delayed(duration, () {
    print('done');
  });
  print('task 2');
}

void task3() {
  print('task 3');
}

 

9.4 Stateful Widget Lifecycle Methods

The lifecycle has the following simplified steps:

  • createState()
  • mounted == true
  • initState()
  • didChangeDependencies()
  • build()
  • didUpdateWidget()
  • setState()
  • deactivate()
  • dispose()
  • mounted == false

 

9.5 Exception Handling and Null Aware Operator

An exception is handle using try..catch:

try {
  // ...
} on SomeException catch(e) {
 //Handle exception of type SomeException
} catch(e) {
 //Handle all other exceptions
}

 

9.6 Application Programming Interface (API), explained

  • see openweathermap.org
  • API = Application Programming Interface
  • An interface to access a complete functionality
  • API is used to communicate between systems

9.7 Networking in Flutter App with HTTP Package

  • head to pub.dev, and search "HTTP"
  • grab the dependency, and put it into pubspec.yaml
  • import the library, try the following code
import 'dart:convert' as convert;

import 'package:http/http.dart' as http;

void main(List<String> arguments) async {
  // This example uses the Google Books API to search for books about http.
  // https://developers.google.com/books/docs/overview
  var url =
      Uri.https('www.googleapis.com', '/books/v1/volumes', {'q': '{http}'});

  // Await the http get response, then decode the json-formatted response.
  var response = await http.get(url);
  if (response.statusCode == 200) {
    var jsonResponse =
        convert.jsonDecode(response.body) as Map<String, dynamic>;
    var itemCount = jsonResponse['totalItems'];
    print('Number of books about http: $itemCount.');
  } else {
    print('Request failed with status: ${response.statusCode}.');
  }
}
import 'package:flutter/material.dart';
import 'package:geolocator/geolocator.dart';
import 'package:http/http.dart' as http;

class LoadingScreen extends StatefulWidget {
  const LoadingScreen({Key? key}) : super(key: key);

  @override
  _LoadingScreenState createState() => _LoadingScreenState();
}

class _LoadingScreenState extends State<LoadingScreen> {
  double lat = 1.0;
  double lon = 1.0;
  String key =
      '76ca741cecc5c03ec7b80d1c781763fb'; // copy dari openweathermap.org

  void getWeather() async {
    var url = Uri.parse(
        'https://api.openweathermap.org/data/2.5/weather?lat=$lat&lon=$lon&appid=$key');
    var response = await http.get(url);
    print(response.statusCode);
    if (response.statusCode == 200) {
      print(response.body);
    }
  }

  void getLocation() async {
    Position position = await Geolocator.getCurrentPosition(
        desiredAccuracy: LocationAccuracy.low);
    print(position);
    lat = position.latitude;
    lon = position.longitude;
  }

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: Container(
        child: Center(
          child: TextButton(
            child: Text('Click Me'),
            onPressed: () {
              getLocation();
              getWeather();
            },
          ),
        ),
      ),
    );
  }
}

9.8 JSON Parsing and Dynamic Type

import 'dart:convert' as convert;

var jsonResponse = convert.jsonDecode(response.body) as Map<String, dynamic>;
var itemCount = jsonResponse['totalItems'];

 

9.9 Getting Actual Data From OpenWeatherMap API

  • go to www.openweathermap.org
  • register a new account
  • copy the key
  • Use the current weather API with the key

 

9.10 Showing Spinner While User Wait

  •  head to pub.dev, and search "flutter spinkit"
  • copy the dependency, and put it into pubspec.yaml
  • create loading_screen.dart, and try the following code
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: Center(
        child: SpinKitSquareCircle(
          color: Colors.white,
          size: 50.0,
        ),
      ),
    );
  }

 

9.11 Passing Data to State Object

Navigator.push(context, MaterialPageRoute(builder: (context) {
  return LocationScreen(data);
}));

class LocationScreen extends StatefulWidget {
  final locationWeather;
  LocationScreen(this.locationWeather);

  @override
  _LocationScreenState createState() => _LocationScreenState();
}

  @override
  void initState() {
    super.initState();
    var data = widget.locationWeather;
    updateUi(data);
  }

 

9.12 Updating The Weather With Weather Model

 

 

9.13 Creating and Styling Text for Text Entry

child: TextField(
    style: TextStyle(
        color: Colors.black,
    ),
    decoration: kTextFieldInputDecoration,
      onChanged: (value) {
      cityName = value;
    },
),

 

9.14 Passing Data Backward Through Navigation Stack

onPressed: () {
   Navigator.pop(context, cityName);
},

 

loading_screen

import 'dart:io';

import 'package:flutter/material.dart';
import 'package:geolocator/geolocator.dart';
import './location_screen.dart';
import 'package:http/http.dart' as http;
import 'dart:convert';
import 'package:flutter_spinkit/flutter_spinkit.dart';

class LoadingScreen extends StatefulWidget {
  const LoadingScreen({Key? key}) : super(key: key);

  @override
  _LoadingScreenState createState() => _LoadingScreenState();
}

class _LoadingScreenState extends State<LoadingScreen> {
  double lat = 1.0;
  double lon = 1.0;
  String key =
      '76ca741cecc5c03ec7b80d1c781763fb'; // copy dari openweathermap.org
  int temp = 0;

  @override
  void initState() {
    super.initState();
    getLocation();
    getWeather(); // tunggu habis proses
  }

  void getWeather() async {
    Duration duration = Duration(seconds: 3);
    await Future.delayed(duration);
    var url = Uri.parse(
        'https://api.openweathermap.org/data/2.5/weather?lat=$lat&lon=$lon&appid=$key&units=metric');
    var response = await http.get(url);
    print(response.statusCode);
    if (response.statusCode == 200) {
      print(response.body);
      var data = jsonDecode(response.body);
      double cel = data['main']['temp'];
      temp = cel.round(); // convert double ke integer
      print(temp);

      Navigator.push(context, MaterialPageRoute(builder: (context) {
        return LocationScreen(temp);
      }));
    }
  }

  void getLocation() async {
    Position position = await Geolocator.getCurrentPosition(
        desiredAccuracy: LocationAccuracy.low);
    print(position);
    lat = position.latitude;
    lon = position.longitude;
  }

  @override
  Widget build(BuildContext context) {
    return Container(
      color: Colors.teal,
      child: Center(
        child: SpinKitCubeGrid(
          color: Colors.white,
          size: 50.0,
        ),
      ),
    );
  }
}

location_screen

import 'package:flutter/material.dart';
import '../services/weather.dart';
import './city_screen.dart';

class LocationScreen extends StatefulWidget {
  final cel;
  LocationScreen(this.cel); // constructor

  @override
  _LocationScreenState createState() => _LocationScreenState();
}

class _LocationScreenState extends State<LocationScreen> {
  int temp = 0;

  @override
  void initState() {
    print('init');
    print(widget.cel);
    super.initState();
    temp = widget.cel;
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: Container(
        decoration: BoxDecoration(
          image: DecorationImage(
            fit: BoxFit.cover,
            image: AssetImage('images/bg2.jpg'),
          ),
        ),
        child: SafeArea(
          child: Column(
            mainAxisAlignment: MainAxisAlignment.spaceBetween,
            children: [
              Container(
                height: 70,
                color: Colors.green,
                child: Row(
                  mainAxisAlignment: MainAxisAlignment.spaceBetween,
                  children: [
                    FlatButton(
                      onPressed: () {},
                      child: Icon(
                        Icons.near_me,
                        size: 50,
                      ),
                    ),
                    FlatButton(
                      onPressed: () async {
                        int temp2 = await Navigator.push(context,
                            MaterialPageRoute(builder: (context) {
                          return CityScreen();
                        }));

                        setState(() {
                          temp = temp2;
                        });
                      },
                      child: Icon(
                        Icons.location_city,
                        size: 50,
                      ),
                    )
                  ],
                ),
              ),
              Text(
                '$temp C',
                style: TextStyle(fontSize: 40, color: Colors.white),
              ),
              Text(
                WeatherModel().getMessage(temp),
                style: TextStyle(fontSize: 30, color: Colors.white),
              )
            ],
          ),
        ),
      ),
    );
  }
}

city_screen

import 'package:flutter/material.dart';
import 'package:http/http.dart' as http;
import 'dart:convert';

class CityScreen extends StatefulWidget {
  const CityScreen({Key? key}) : super(key: key);

  @override
  _CityScreenState createState() => _CityScreenState();
}

class _CityScreenState extends State<CityScreen> {
  String city = '';

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: SafeArea(
        child: Padding(
          padding: const EdgeInsets.all(20.0),
          child: Column(
            mainAxisAlignment: MainAxisAlignment.center,
            children: [
              TextField(
                onChanged: (val) {
                  print(val);
                  city = val;
                },
                decoration: InputDecoration(
                  hintText: 'City Name...',
                ),
              ),
              ElevatedButton(
                onPressed: () async {
                  // call API
                  int temp = await getTemp();
                  Navigator.pop(context,
                      temp); // return ke screen sebelum / screen 2 (location_screen)
                },
                child: Text('Get Weather'),
              ),
            ],
          ),
        ),
      ),
    );
  }

  // return temperature bagi bandar yg di key-in
  Future<int> getTemp() async {
    String key = '76ca741cecc5c03ec7b80d1c781763fb';
    var url = Uri.parse(
        'https://api.openweathermap.org/data/2.5/weather?q=$city&appid=$key&units=metric');
    var response = await http.get(url);
    print(response.statusCode);
    if (response.statusCode == 200) {
      print(response.body);
      var data = jsonDecode(response.body);
      double cel = data['main']['temp'];
      int temp = cel.round(); // convert double ke integer
      return temp;
    } else {
      return 0;
    }
  }
}

Weather

class WeatherModel {
  String getMessage(int temp) {
    if (temp > 25) {
      return 'Jom makan aiskrim';
    } else if (temp > 20) {
      return 'Jom kita bersia-siar';
    } else {
      return 'Bawa baju sejuk';
    }
  }
}

 

Borang Penilaian Keberkesanan Latihan

Training evaluation ยท Flutter Beginner

Log in with the account you registered for this training to fill in the survey.

Log in to fill in the survey

Attendance

Registration closed
This training ended on 7 Aug 2021, so new attendance can no longer be registered.

Students (15)

# Name
1. MIRA ARYANE BINTI MANSOR
2. shamsudin b mat ali
3. Nor Azah binti Abu Bakar
4. NORZALINA BINTI GHAZALI
5. AZDAN HARIZ BIN AHMAD
6. Masliyana Azmi
7. Ainon binti Mat Jusoh
8. RAFIZAH ABDUL RAHMAN
9. Mohd Firdaus
10. NOR AZWA BINTI ABAS
11. JUHANAWATI BINTI HASSAN
12. SITI NORHAFIZAH BT ROSLI
13. MOHD FAUZI BIN MANSOR
14. NORWAHIDAH WAHID
15. NORFAZILAH BINTI TOMPANG@MOHD ZAIN