This week we will be learning the basics of Flutter. Flutter is a cross-platform mobile app development framework that allows you to write code once and deploy it to both iOS and Android. Flutter uses the Dart programming language, which is similar to Java and JavaScript.
By the end of this week, you should be able to:
- Create a Flutter project
- Run a Flutter project on an emulator or physical device
- Use the Flutter documentation to learn about widgets
- Create a simple Flutter app with one page using stateless widgets
- file management
Here are some resources to help you with this week's assignment:
- Flutter - Beautiful native apps in record time
- Flutter - Get started: install
- Flutter - Get started: test drive
- Flutter - Building layouts
- Flutter Basic Widgets
- Stateful vs Stateless
- Flutter CodeLab
- Custom Themes
- Short Video
You will create a simple weather app that displays the current weather conditions for a given location. This will only be front-end development, so you will not need to worry about fetching data from an API.
- Fork this repository
- Clone your forked repository to your computer
- Open the folder you just cloned in VS Code
- Extensions to install:
- Dart
- Flutter
- Awesome Flutter Snippets
- Flutter Widget Snippets
- Pubspec Assist
- Material Icon Theme
- Extensions to install:
- Android Virtual device
- Install Android Studio
- Open Android Studio
- Click on the AVD Manager icon
- Create a new virtual device
- Run the virtual device
- Run the following command:
flutter doctor
- This will tell you if you have any issues with your Flutter installation
flutter devices
- This will tell you if you have any issues with your Android Virtual Device
flutter pub get
- This will install all of the dependencies in your
pubspec.yaml
file
- This will install all of the dependencies in your
flutter run
- This will run your app on your Android Virtual Device
- Go into the
lib
folder and openmain.dart
import 'package:flutter/material.dart';
void main() {
runApp(const MainApp());
}
class MainApp extends StatelessWidget {
const MainApp({super.key});
@override
Widget build(BuildContext context) {
return const MaterialApp(
home: Scaffold(
body: Center(
child: Text('Hello World!'),
),
),
);
}
}
- The
main()
function is the entry point of the app. It is where the app starts executing. - The
runApp()
function takes a widget and runs it. In this case, we are running theMainApp
widget. - The
MainApp
widget is a stateless widget. Stateless widgets are immutable, meaning that their properties can't change—all values are final. This widget does not have to be calledMainApp
, but it is good practice to name your widget the same as your file. - The
MainApp
widget has abuild()
method that returns a widget. This is the widget that will be displayed when the app is launched. - The
MainApp
widget returns aMaterialApp
widget. TheMaterialApp
widget is a widget that provides a framework for implementing the basic material design layout of your app.
MaterialApp(
title: 'Weather App',
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: const Scaffold(),
debugShowCheckedModeBanner: false,
);
- The
MaterialApp
widget is the root widget of your app. It is what allows you to use Material Design components in your app. - The
MaterialApp
widget has ahome
property that takes a widget. This is the widget that will be displayed when the app is launched. - The
MaterialApp
widget also has atheme
property that takes aThemeData
object. This is where you can customize the theme of your app. - The
MaterialApp
widget also has atitle
property that takes a string. This is the title of your app that will be displayed in the app switcher. - The
MaterialApp
widget also has adebugShowCheckedModeBanner
property that takes a boolean. This is whether or not you want the debug banner to be displayed in the top right corner of your app.
Scaffold(
appBar: AppBar(
title: const Text('Weather App'),
),
body: const Center(
child: Text('Hello World!'),
),
floatingActionButton: FloatingActionButton(
onPressed: () {},
child: const Icon(Icons.add),
),
);
- The
Scaffold
widget is a widget that provides a framework for implementing the basic material design layout of your app. - The
Scaffold
widget has abody
property that takes a widget. This is the widget that will be displayed in the body of the scaffold. - The
Scaffold
widget also has anappBar
property that takes aAppBar
widget. This is the widget that will be displayed in the app bar of the scaffold. - The
Scaffold
widget also has afloatingActionButton
property that takes a widget. This is the widget that will be displayed in the bottom right corner of the scaffold.
Row(
mainAxisAlignment: MainAxisAlignment.center,
children: const [
Text('Hello'),
Text('World'),
],
);
- The
Row
widget is a widget that displays its children in a horizontal array. - The
Row
widget has amainAxisAlignment
property that takes aMainAxisAlignment
enum. This is how the children of the row will be aligned. - The
Row
widget also has acrossAxisAlignment
property that takes aCrossAxisAlignment
enum. This is how the children of the row will be aligned vertically. - The
Row
widget also has achildren
property that takes a list of widgets. These are the widgets that will be displayed in the row.
Column(
mainAxisAlignment: MainAxisAlignment.center,
children: const [
Text('Hello'),
Text('World'),
],
);
- The
Column
widget is a widget that displays its children in a vertical array. - The
Column
widget has amainAxisAlignment
property that takes aMainAxisAlignment
enum. This is how the children of the column will be aligned. - The
Column
widget also has acrossAxisAlignment
property that takes aCrossAxisAlignment
enum. This is how the children of the column will be aligned horizontally. - The
Column
widget also has achildren
property that takes a list of widgets. These are the widgets that will be displayed in the column.
Container(
width: 100,
height: 100,
color: Colors.blue,
decoration: const BoxDecoration(
shape: BoxShape.circle,
),
child: const Text('Hello World!'),
);
- The
Container
widget is a widget that allows you to customize the size, color, and child of a widget. - The
Container
widget has awidth
property that takes a double. This is the width of the container. - The
Container
widget also has aheight
property that takes a double. This is the height of the container. - The
Container
widget also has acolor
property that takes aColor
object. This is the color of the container. - The
Container
widget also has achild
property that takes a widget. This is the widget that will be displayed inside the container.
SizedBox(
width: 100,
height: 100,
child: const Text('Hello World!'),
);
- The
SizedBox
widget is a widget that allows you to customize the size of a widget. - The
SizedBox
widget has awidth
property that takes a double. This is the width of the sized box. - The
SizedBox
widget also has aheight
property that takes a double. This is the height of the sized box. - The
SizedBox
widget also has achild
property that takes a widget. This is the widget that will be displayed inside the sized box.
SingleChildScrollView(
scrollDirection: Axis.horizontal,
physics: const BouncingScrollPhysics(),
child: Column(
children: const [
Text('Hello'),
Text('World'),
],
),
);
- The
SingleChildScrollView
widget is a widget that allows you to scroll through its children. - The
SingleChildScrollView
widget has achild
property that takes a widget. This is the widget that will be displayed inside the scroll view. - The
SingleChildScrollView
widget also has ascrollDirection
property that takes aAxis
enum. This is the direction that the scroll view will scroll in. - The
SingleChildScrollView
widget also has aphysics
property that takes aScrollPhysics
object. This is the physics of the scroll view.
CircleAvatar(
radius: 50,
backgroundImage: NetworkImage(
'https://picsum.photos/200',
),
);
- The
CircleAvatar
widget is a widget that displays an image in a circle. - The
CircleAvatar
widget has aradius
property that takes a double. This is the radius of the circle. - The
CircleAvatar
widget also has abackgroundImage
property that takes anImageProvider
object. This is the image that will be displayed in the circle. - The
CircleAvatar
widget also has achild
property that takes a widget. This is the widget that will be displayed inside the circle.
- Go into the
pubspec.yaml
file - Under the
flutter
section, you'll see aassets
section - Add the following code to the
assets
section:
- assets/images/
- This will tell Flutter to look in the
assets/images/
folder for any assets that you want to use in your app - Save the
pubspec.yaml
file
- create a folder called
images
in theassets
folder - add an image to the
images
folder
- There are two ways to add an image to your app
AssetImage
- This is used for images that are stored locally in your app
NetworkImage
- This is used for images that are stored on the internet
Image(
image: AssetImage('assets/images/image.png'),
);
- The
Image
widget is a widget that displays an image. - The
Image
widget has animage
property that takes anImageProvider
object. This is the image that will be displayed. - The
AssetImage
widget is a widget that displays an image that is stored locally in your app.
Image(
image: NetworkImage('https://picsum.photos/200'),
);
- The
NetworkImage
widget is a widget that displays an image that is stored on the internet. - The
NetworkImage
widget has aurl
property that takes a string. This is the url of the image that will be displayed. - The
Image
widget is a widget that displays an image.
Container(
width: 100,
height: 100,
decoration: BoxDecoration(
image: DecorationImage(
image: AssetImage('assets/images/image.png'),
),
),
);
- The
Container
widget is a widget that allows you to customize the size, color, and child of a widget. - The
Container
widget has adecoration
property that takes aBoxDecoration
object. This is the decoration of the container. - The
BoxDecoration
widget is a widget that allows you to customize the decoration of a container. - The
BoxDecoration
widget has animage
property that takes aDecorationImage
object. This is the image that will be displayed in the container.
- Go into the
lib
folder and create a folder calledwidgets
- Create a file called
details_row.dart
in thewidgets
folder
import 'package:flutter/material.dart';
class DetailsRow extends StatelessWidget {
const DetailsRow({
super.key,
required this.text,
required this.icon,
});
final String text;
final Icon icon;
@override
Widget build(BuildContext context) {
return Row(
mainAxisAlignment: MainAxisAlignment.spaceAround,
children: [
icon,
Text(
text,
style: const TextStyle(
color: Colors.black,
fontSize: 20,
fontWeight: FontWeight.bold,
),
),
const SizedBox(),
],
);
}
}
- The
DetailsRow
widget is a widget that displays a row of details. - We have created a custom widget called
DetailsRow
that takes two properties:text
andicon
. - The
text
property is a string that will be displayed in the row. - The
icon
property is an icon that will be displayed in the row.
- Go into the
main.dart
file - Import the
DetailsRow
widget
import 'widgets/details_row.dart';
- Use the
DetailsRow
widget
DetailsRow(
text: 'Feels Like 70°',
icon: const Icon(
Icons.thermostat_outlined,
color: Colors.black,
),
),
- Go into the
lib
folder and create a folder calledscreens
- Create a file called
home_screen.dart
in thescreens
folder
import 'package:flutter/material.dart';
class HomeScreen extends StatelessWidget {
const HomeScreen({
super.key,
});
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: const Text('Weather App'),
),
body: const Center(
child: Text('Hello World!'),
),
floatingActionButton: FloatingActionButton(
onPressed: () {},
child: const Icon(Icons.add),
),
);
}
}
- The
HomeScreen
page is a widget that displays the home screen of the app. - We have created a custom page called
HomeScreen
. - The
HomeScreen
page is a stateless widget. Stateless widgets are immutable, meaning that their properties can't change—all values are final. This widget does not have to be calledHomeScreen
, but it is good practice to name your widget the same as your file.
- Go into the
main.dart
file - Import the
HomeScreen
page
import 'screens/home_screen.dart';
- Use the
HomeScreen
page
MaterialApp(
title: 'Weather App',
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: const HomeScreen(),
debugShowCheckedModeBanner: false,
);
Your job is to create a single page weather app that displays the current weather conditions for a given location. This will only be front-end development, so you will not need to worry about fetching data from an API.
The design of the app is up to you, and you can use any resources you want to help you with the design. You can use the Flutter Gallery as a reference.
However, The structure of the app should follow the requirements below.
- The app should have a screens folder containing any screen created in a separate file
- The app should have a widgets folder containing any custom widgets created in a separate file
- The app should have a models folder containing any models created in a separate file (Example, WeatherStatusModel)
- Create a simple layout for the app that includes a text field for entering a location and a button to submit the location.
- Display the current weather conditions for the location in a card or container.