Flutter

3. Dart Primer

You can practice the grammer of Dart language in the below link

when you want to just print something in Dart language

1
2
3
void main() {
print('hello');
}

about variables

Dart language doesn’t support dynamical variable type basically. as like another languages.

if you want to use it, you should declare ‘dynamic’ keyword in front of the variable data.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
void main() {
int age = 30;
print(age);

String name = "chun-li";
print(name);

bool isNight = false;
print(isNight);

dynamic dyName = 'chun-li';
dyName = 30;
print(dyName);

}

about functions

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
void main() {
String greet = greeting();
print(greet);
int age = getAge();
print(age);
String arrowGreet = arrowGreeting();
print(arrowGreet);
}

String greeting() {
return 'hello';
}

String arrowGreeting() => 'hello';

int getAge() {
return 30;
}

() {} // anonymous function

about List

It’s really similar with Java programming language. if you don’t declare the type of List then this is operated as the list as a dynamic typed.

1
2
3
4
5
6
7
8
9
10
11
12
13
void main() {
List untypedNames = ['chun-li', 'yoshi', 'mario'];

untypedNames.add('luigi');
untypedNames.remove('yoshi');
untypedNames.add(30);
print(untypedNames);

List<String> typedNames = ['chun-li', 'yoshi', 'mario'];
typedNames.add('luigi');
typedNames.remove('yoshi');
print(typedNames);
}

about class

4. Creating a Flutter App in Android Studio

First of all, You should turn on the android studio app and install the ‘flutter’ plugin.

1
Double shift > Search 'plugins' > Search flutter > install the flutter app.

1
File > New > New Flutter Project

Flutter SDK path is the location of the git projecty you already cloned like from the below command.

1
git clone https://github.com/flutter/flutter.git -b stable

The below code is the main entry point of this Flutter app. as you learned before, main() method is the entry point of dart programming language. and It’s same with Java programming language.

1
2
3
4
5
// main.dart

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

MyApp class inherit StatelessWidget. What i am saying is MyApp is the root Widget in our Flutter app. and Flutter concept is all of components of flutter are consisted of Widgets. and Widget is represented by a class syntax of Dart language.

1
2
3
4
5
// main.dart

class MyApp extends StatelessWidget {
// ...
}

The below code runs our own MaterialApp.

1
2
3
4
5
void main() {
runApp(MaterialApp(
home: Text('hey ninjas!'),
));
}

5. Scaffold & AppBar Widgets

Scaffold widget is going to allow us to implement a basic layout for our app. otherwords, Scaffold widget basically like a wrapper to a few different layout widgets things like the app bar, the body and also floating action button.

You can get the more detail at the below link.

in Flutter, if You want to insert some texts into widget, You should always use Text() widget

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
void main() {
runApp(MaterialApp(
home: Scaffold(
appBar: AppBar(
title: Text('my first app'),
centerTitle: true,
),
body: Center(
child: Text('hello ninjas!'),
),
floatingActionButton: FloatingActionButton(
onPressed: () { },
child: Text('click'),
),
),

));
}

6. Colours & Font

You can get free google fonts from the below link

let’s create new folder named ‘fonts’ in your app root directory and please move your font files downloaded from fonts.google.com site in there.

pubspec.yaml file is a configuration file about your flutter app. You should know one thing that the format in this file is really important.

if you don’t keep the two spaces between each code then it will be not operated well.

7. Stateless Widgets & Hot Reload

We should consider when we create new custom widget whether is stateless widget or stateful widget.

  • Stateless Widgets

    • the state of the widget cannot change over time
    • ex) Layout, Color
  • Stateful Widgets

    • the state of the widget can change over time
    • ex) data

the one of the reason why the widgets are separated as Stateless widget or Stateful widget is hot reload.

The flutter should catch the change of the widgets for implementing hot-reload function. so that defining whether your widget is stateful or not is needed.

The build() function in StatelessWidget is what is responsible for building up the widget tree inside the stateless home widgets so all of the stuff in build() function whenever we make a change to the code inside this widget tree flutter is going to detect that when we save it and it’s going to cause the build() function to rerun.
that’s is hot reload in action.

so if you create the widget inherited Stateless thing then the flutter will re run build() function when you save your code.

8. Images & Assets

The principle of Assets is same with font. You should change the pubspec.yaml file in your flutter app.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
class Home extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Scaffold(
// ...

body: Center(
child: Image.asset('assets/space-1.jpg')
),

// ...
);
}
}
1
2
3
4
5
6
7
flutter:

## ...

assets:
- assets/

9. Buttons & Icons

Icon is really simple

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
class Home extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Scaffold(
// ...

body: Center(
child: Icon(
Icons.airport_shuttle,
color: Colors.lightBlue,
size: 50.0,
)
),

// ...
);
}
}

RaisedButton means that itself has a shadow.

it has a little shadow it’s raising it away from the page giving it that kind of 3D effect.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
class Home extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Scaffold(
// ...

body: Center(
child: RaisedButton(
onPressed: () {
print('you clicked me');
},
child: Text('click me'),
color: Colors.lightBlue,
)
),

// ...
);
}
}

and Flatbutton doesn’t have a shawdow unlike RaisedButton.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
class Home extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Scaffold(
// ...
body: Center(
child: FlatButton(
onPressed: () {
print('you clicked me');
},
child: Text('click me'),
color: Colors.lightBlue,
)
),

// ...
);
}
}

if you want use a button with texts and icons then you should use RaisedButton.icon() widget or IconButton widget.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
class Home extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Scaffold(
// ...
body: Center(
child: RaisedButton.icon(
onPressed: () {},
icon: Icon(
Icons.mail
),
label: Text('mail me'),
color: Colors.amber,
)
),

// ...
);
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
class Home extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Scaffold(
// ...

body: Center(
child: IconButton(
onPressed: () {
print('you clicked me');
},
icon: Icon(Icons.alternate_email),
color: Colors.amber,
)
),

// ...
);
}
}

10. Containers & Padding

the container is only the same size as the widget inside it. if we don’t have a child which inside it then the container takes up the whole room available. but it has a child widget like a text widget then the container restricts itself to the size of that child widget.

About EdgeInsets

  • symmetric : top = bottom, left = right
  • fromLTRB : each individual values
  • all : having same value all of them.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
class Home extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Scaffold(
// ...

body: Container(
padding: EdgeInsets.fromLTRB(10.0, 20.0, 30.0, 40.0),
margin: EdgeInsets.all(30.0),
color: Colors.grey[400],
child: Text('hello'),
),

// ...
);
}
}

if you only need a padding option then you can type the code like the below. but you should know Padding widget doesn’t have another properties like margins, colors and so on.

Padding widget is a padding itself. so You should don’t be misunderstanding. if you need to use all of the properties then you can use Container widget as you did it.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
class Home extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Scaffold(
// ...
body: Padding(
padding: EdgeInsets.all(90.0),
child: Text('hello'),
),

// ...
);
}
}

11. Rows

Rows widget can align your widgets what should be located in Rows children property. It’s like a flexbox in CSS technique.

main axis is the direction of the row. ad the cross axis is the perpendicular direction.

MainAxisAlignment.start option is default.
CrossAxisAlignment.start option is default also.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
class Home extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Scaffold(
// ...

body: Row(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
Text('hello, world'),
FlatButton(
onPressed: () {},
color: Colors.amber,
child: Text('click me'),
),
Container(
color: Colors.cyan,
padding: EdgeInsets.all(30.0),
child: Text('inside container'),
)
],
),

// ...
);
}
}

12. Columns

Columns axis is opposite with Rows one. the main axis in a column is vertical and the cross axis in a column is horizontal.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
class Home extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Scaffold(

// ...

body: Column(
mainAxisAlignment: MainAxisAlignment.end,
crossAxisAlignment: CrossAxisAlignment.end,
children: <Widget>[
Row(
children: <Widget>[
Text('hello,'),
Text(' world'),
],
),
Container(
padding: EdgeInsets.all(20.0),
color: Colors.cyan,
child: Text('one'),
),
Container(
padding: EdgeInsets.all(30.0),
color: Colors.pinkAccent,
child: Text('two'),
),
Container(
padding: EdgeInsets.all(40.0),
color: Colors.amber,
child: Text('three'),
),
],
),

// ...
);
}
}

14. Expanded Widgets

we stil have second and third containers the same size which is the size of the content inside it but the first container now because it’s inside the expanded widget over here it’s taking up all the available space left over.

flex property in Expanded widget is a portion of the width that we want it to take up. they’re basically fractions of the whole width that they take up.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
class Home extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Scaffold(

// ...

body: Row(
children: <Widget>[
Expanded(
child: Image.asset('assets/space-2.jpg'),
flex: 3,
),
Expanded(
flex: 1,
child: Container(
padding: EdgeInsets.all(30.0),
color: Colors.cyan,
child: Text('1'),
),
),
Expanded(
flex: 1,
child: Container(
padding: EdgeInsets.all(30.0),
color: Colors.pinkAccent,
child: Text('2'),
),
),
Expanded(
flex: 1,
child: Container(
padding: EdgeInsets.all(30.0),
color: Colors.amber,
child: Text('3'),
),
)
],
),

// ...
);
}
}

15. Ninja ID Project

I remember scaffold allows us to quickly make a layout for our app things like an app bar and the body all that kind of stuff.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
void main() {
runApp(MaterialApp(
home: NinjaCard(),
));
}

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

@override
Widget build(BuildContext context) {
return Scaffold(
backgroundColor: Colors.grey[900],
appBar: AppBar(
title: Text('Ninja ID Card'),
centerTitle: true,
backgroundColor: Colors.grey[850],
elevation: 0.0,
),
body: Padding(
padding: EdgeInsets.fromLTRB(30.0, 40.0, 30.0, 0.0),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
Center(
child: CircleAvatar(
backgroundImage: AssetImage('assets/thumb.jpg'),
radius: 40.0,
),
),
Divider(
height: 90.0,
color: Colors.grey[800],
),
Text(
'NAME',
style: TextStyle(
color: Colors.grey,
letterSpacing: 2.0,
),
),
SizedBox(height: 10.0),
Text(
'Chun-Li',
style: TextStyle(
color: Colors.amberAccent[200],
letterSpacing: 2.0,
fontSize: 28.0,
fontWeight: FontWeight.bold,
),
),
SizedBox(height: 30.0),
Text(
'CURRENT NINJA LEVEL',
style: TextStyle(
color: Colors.grey,
letterSpacing: 2.0,
),
),
SizedBox(height: 10.0),
Text(
'8',
style: TextStyle(
color: Colors.amberAccent[200],
letterSpacing: 2.0,
fontSize: 28.0,
fontWeight: FontWeight.bold,
),
),
SizedBox(height: 30.0),
Row(
children: <Widget>[
Icon(
Icons.email,
color: Colors.grey[400],
),
SizedBox(width: 10.0),
Text(
'chun.li@thenetninja.co.uk',
style: TextStyle(
color: Colors.grey[400],
fontSize: 18.0,
letterSpacing: 1.0
),
)
],
)
],
),
),
);
}
}

16. Stateful Widgets

setState() function takes in as an argument a function itself. this is a trigger of the build function sp then it rebuilt it with the new state. whenever we want to change the state or the data inside a state for Widget what we have to do is use setState() function. this is only way when we use set state that triggers the build function to rerun.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
class NinjaCard extends StatefulWidget {
const NinjaCard({Key? key}) : super(key: key);

@override
State<NinjaCard> createState() => _NinjaCardState();
}

class _NinjaCardState extends State<NinjaCard> {

int ninjaLevel = 0;

@override
Widget build(BuildContext context) {
return Scaffold(
backgroundColor: Colors.grey[900],
appBar: AppBar(
title: Text('Ninja ID Card'),
centerTitle: true,
backgroundColor: Colors.grey[850],
elevation: 0.0,
),
floatingActionButton: FloatingActionButton(
onPressed: () {
setState(() {
ninjaLevel += 1;
});
},
child: Icon(Icons.add),
backgroundColor: Colors.grey[800],
),
body: Padding(
padding: EdgeInsets.fromLTRB(30.0, 40.0, 30.0, 0.0),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
Center(
child: CircleAvatar(
backgroundImage: AssetImage('assets/thumb.jpg'),
radius: 40.0,
),
),
Divider(
height: 90.0,
color: Colors.grey[800],
),
Text(
'NAME',
style: TextStyle(
color: Colors.grey,
letterSpacing: 2.0,
),
),
SizedBox(height: 10.0),
Text(
'Chun-Li',
style: TextStyle(
color: Colors.amberAccent[200],
letterSpacing: 2.0,
fontSize: 28.0,
fontWeight: FontWeight.bold,
),
),
SizedBox(height: 30.0),
Text(
'CURRENT NINJA LEVEL',
style: TextStyle(
color: Colors.grey,
letterSpacing: 2.0,
),
),
SizedBox(height: 10.0),
Text(
'$ninjaLevel',
style: TextStyle(
color: Colors.amberAccent[200],
letterSpacing: 2.0,
fontSize: 28.0,
fontWeight: FontWeight.bold,
),
),
SizedBox(height: 30.0),
Row(
children: <Widget>[
Icon(
Icons.email,
color: Colors.grey[400],
),
SizedBox(width: 10.0),
Text(
'chun.li@thenetninja.co.uk',
style: TextStyle(
color: Colors.grey[400],
fontSize: 18.0,
letterSpacing: 1.0
),
)
],
)
],
),
),
);
}
}

17. Lists of Data

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
void main() {
runApp(MaterialApp(
home: QuoteList(),
));
}

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

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

class _QuoteListState extends State<QuoteList> {

List<String> quotes = [
'Be yourself; everyone else is already taken',
'I have nothing to declare except my genius',
'The truth is rarely pure and never simple'
];

@override
Widget build(BuildContext context) {
return Scaffold(
backgroundColor: Colors.grey[200],
appBar: AppBar(
title: Text('Awesome Quotes'),
backgroundColor: Colors.redAccent,
),
body: Column(
children: quotes.map((quote) => Text(quote)).toList(),
),
);
}
}

18. Custom Classes

1
2
3
4
5
6
7
8
9
10
11
// Quote.dart

class Quote {

String text;
String author;

Quote({ this.text = "", this.author = "" });
}

Quote myQuote = Quote(text: 'this is the qite text', author: 'oscar wilde');
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
// main.dart

// ...

class _QuoteListState extends State<QuoteList> {

List<Quote> quotes = [
Quote(author: 'Osca Wilde', text: 'Be yourself; everyone else 1'),
Quote(author: 'Osca Wilde', text: 'Be yourself; everyone else 2'),
Quote(author: 'Osca Wilde', text: 'Be yourself; everyone else 3')
];

@override
Widget build(BuildContext context) {
return Scaffold(
// ...

body: Column(
children: quotes.map((quote) => Text('${quote.text} - ${quote.author}')).toList(),
),
);
}
}

19. Cards

https://api.flutter.dev/flutter/material/Card-class.html

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
class _QuoteListState extends State<QuoteList> {

// ...

Widget quoteTemplate(quote) {
return Card(
margin: EdgeInsets.fromLTRB(16.0, 16.0, 16.0, 0.0),
child: Padding(
padding: const EdgeInsets.all(12.0),
child: Column(
crossAxisAlignment: CrossAxisAlignment.stretch,
children: <Widget>[
Text(
quote.text,
style: TextStyle(
fontSize: 18.0,
color: Colors.grey[600],
),
),
SizedBox(height: 6.0),
Text(
quote.author,
style: TextStyle(
fontSize: 14.0,
color: Colors.grey[800]
),
)
],
),
),
);
}

@override
Widget build(BuildContext context) {
return Scaffold(
// ...
body: Column(
children: quotes.map((quote) => quoteTemplate(quote)).toList(),
),
);
}
}

20. Extracting Widgets

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
import 'package:flutter/material.dart';
import 'package:quotes/quote.dart';

class QuoteCard extends StatelessWidget {

final Quote quote;
QuoteCard({ required this.quote });

@override
Widget build(BuildContext context) {
return Card(
margin: EdgeInsets.fromLTRB(16.0, 16.0, 16.0, 0.0),
child: Padding(
padding: const EdgeInsets.all(12.0),
child: Column(
crossAxisAlignment: CrossAxisAlignment.stretch,
children: <Widget>[
Text(
quote.text,
style: TextStyle(
fontSize: 18.0,
color: Colors.grey[600],
),
),
SizedBox(height: 6.0),
Text(
quote.author,
style: TextStyle(
fontSize: 14.0,
color: Colors.grey[800]
),
)
],
),
),
);
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
import 'package:flutter/material.dart';
import 'package:quotes/quote.dart';
import 'quote_card.dart';

// ...

class _QuoteListState extends State<QuoteList> {

// ...

@override
Widget build(BuildContext context) {
return Scaffold(
// ...
body: Column(
children: quotes.map((quote) => QuoteCard(quote: quote)).toList(),
),
);
}
}

21. Function Arguments

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
// quote_card.dart

class QuoteCard extends StatelessWidget {

final Quote quote;
final Function() delete;
QuoteCard({ required this.quote, required this.delete });

@override
Widget build(BuildContext context) {
return Card(
// ...
FlatButton.icon(
onPressed: delete,
label: Text('delete quote'),
icon: Icon(Icons.delete)
// ...
);
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
class _QuoteListState extends State<QuoteList> {
// ...

@override
Widget build(BuildContext context) {
// ...
delete: () {
setState(() {
quotes.remove(quote);
});
}
// ...
}
}

23. Maps & Routing

Navigator.pushNamed() is named because we’re going to supply a named round we’re going to use the name of one o the routes to that router and then it’s called push because essentially what we do is push another screen on top of the screen. the screen is still going to exist underneath it’s just that we’re pushing another one on top of it.

It is important concept to understand and we are going to be doing more routing as we go through the rest of this course so that we can see different ways to push and pop routes on and off this kind of stack and manage our routes in an efficient way.

24. Widget Lifecycle

  • Stateless

    • State does not change over time
    • build function only runs once
  • Stateful

    • State Can change over time
    • setState() triggers the build function
  • initState()

    • called only once when the widget is created
    • subscribe to streams or any object that could change our widget data
  • build()

    • builds the widget tree
    • a build is triggered every time we use setState()
  • dispose()

    • when the widget / set object is removed

25. Asynchronous Code

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
class _ChooseLocationState extends State<ChooseLocation> {

void getData() async {

// simulate network request for a username
String username = await Future.delayed(Duration(seconds: 3), () {
return 'yoshi';
});

// simulate network request to get bio of the username
String bio = await Future.delayed(Duration(seconds: 2), () {
return 'vegan, musician & egg collector';
});

print('$username - $bio');

}

int counter = 0;

@override
void initState() {
super.initState();
getData();
print('hey there');
}

// ...
}

26. Flutter Packages (http)

1
2
3
4
dependencies:
flutter:
sdk: flutter
http: ^0.12.0+2
1
2
3
4
5
6
7
8
9
10
11
class _LoadingState extends State<Loading> {

void getData() async {
Response response = await get('https://jsonplaceholder.typicode.com/todos/1');
Map data = jsonDecode(response.body);
print(data);
print(data['title']);
}

// ...
}

28. WorldTime Custom Class

the funcion with async is going to take some time to do it might take two seconds today because we have to go out and reach the data and bring it back.

you should remember if we run an asynchronous function this doesn’t stop the code from carrying on. it just does this in the background and then the rest of the code carries on.

to solve what it would be nice to do is maybe put await keyword in front of an asynchronous function. then we’re waiting for this to finish before it carries on.

for that we should return specific type that we need in an asynchronous function if we want to use the await keyword in front of a cuson aynchronous function we have to place the Future keyword with return type.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
// world_time.dart

class WorldTime {

String location; // location name for the UI
late String time; // the time in that location
String flag; // url to an asset flag icon
String url; // location url for api endpoint

WorldTime({ required this.location, required this.flag, required this.url });

Future<void> getTime() async {
// make the request
Response response = await get('http://worldtimeapi.org/api/timezone/$url');
Map data = jsonDecode(response.body);
print(data);

// get properties from data
String datetime = data['datetime'];
String offset = data['utc_offset'].substring(1, 3);
// print(datetime);
// print(offset);

// create DateTime object
DateTime now = DateTime.parse(datetime);
now.add(Duration(hours: int.parse(offset)));

// set the time property
time = now.toString();
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
class _LoadingState extends State<Loading> {

String time = 'loading';

void setupWorldTime() async {
WorldTime instance = WorldTime(location: 'Berlin', flag: 'germany.png', url: 'Europe/Berlin');
await instance.getTime();
print(instance.time);
setState(() {
time = instance.time;
});
}

@override
void initState() {
super.initState();
setupWorldTime();
}

@override
Widget build(BuildContext context) {
return Scaffold(
body: Padding(
padding: EdgeInsets.all(50.0),
child: Text(time),
),
);
}
}

reference

https://github.com/iamshaunjp/flutter-beginners-tutorial

Share