Vous êtes sur la page 1sur 60

Développement Mobile Native Cross Platform : Flutter

Flutter Approach

Flutter Widgets
Cupertino
Material Design
Native
ARM
Binary
Code
Platform
Channels

Mohamed Youssfi
Laboratoire Signaux Systèmes Distribués et Intelligence Artificielle (SSDIA)
ENSET, Université Hassan II Casablanca, Maroc
Email : med@youssfi.net
Supports de cours : http://fr.slideshare.net/mohamedyoussfi9
Chaîne vidéo : http://youtube.com/mohamedYoussfi
Recherche : http://www.researchgate.net/profile/Youssfi_Mohamed/publications
Flutter ?
• Flutter est un Framework développé par Google, Flutter Approach
qui permet de créer des applications
natives Android et/ou IOS. En utilisant le langage
de programmation DART Flutter Widgets
Cupertino
Material Design
Native
• La version 1.0 de Flutter a été annoncé le 4 ARM
décembre 2018. Binary
Code
• Dart est un langage de programmation développé par la Platform
Channels
communauté Google. La première version date de 2011.

• Le but du développement de ce langage est de


remplacer Javascript afin d'éviter les limites de
performance de ce dernier.

• Dart a trouvé sa popularité à travers Flutter qui offre une


manière typiquement différente pour développer les
applications Mobile Cross Platform telle que IONIC et
React Native
Développement Mobile Cross Platform
Hybrid Approach : IONIC, PhoneGap, Mobile First Flutter Approach

Flutter Widgets
Web View Cupertino
Material Design
HTML Native
CSS ARM
Java Binary
Script Code
Platform
Channels

• Hybrid Approach (IONIC):


• Utilise le moteur de rendu HTML, CSS du Web View pour la logique présentation
Native Cross Plaform Approach : React Native
• Utilise du Java Script pour exécuter les traitements
• Pour accéder aux fonctionnalités natives de l’appareil mobile, il utilise un Bridge (Plugings
CORDOVA)
OEM Widgets
• React Native :
(Capertini, Materal • Utilise ses proposes Composants pour la logique présentation, qui seront mappé en
Design) composant OEM Natif de l’appareil Mobile
Bridge: • Utilise Java Script pour les traitements avec React JS Comme Framework
Java
• Utilise un Bridge Java Script pour accéder aux fonctionnalités Natives
Script Java Script
• Flutter :
(Reactive) Bridge
• Utilise ses propres composants natifs pour la logique présentation. Flutter utilise son propore
(Reactive)
moteur de rendu SKIA pour dessiner les éléments de l’interface.
• Utilise Native ARM Binary Code pour la logique applicative
• Utilise un Channel pour la transmission de message aux fonctionnalités natives
DART
• Dart est utilisé pour écrire
• Des scripts simples
• ou des applications complètes
• Mobile (Android et IOS)
• Web,
• Script de ligne de commande
• Application côté serveur,
• Dart Native:
• Pour les applications ciblant les appareils (mobile, DeskTop, Serveur, etc.),
• Comprend à la fois une machine virtuelle Dart avec compilation
• JIT (Just In Time)
• AOT (Ahead-of-time)) pour produire du code machine.
• Dart Web:
• Pour les applications Web, Dart Web comprend à la fois
• Un compilateur dartdevc (Developpement Time Compiler) : Permet d’exécuter et de débuguer les applications web dart sur le moteur
Chrome en utilisant WebDev Serve tool.
• un compilateur dart2js (Production Time Compiler)
• Pour faire du Dat Web :
• Flutter Framework
• AngularDart
Architecture d’une application Mobile Flutter : Widget
• In Flutter, Everything is a widget. Widgets are basically user
interface components used to create the user interface of the
application.
• For example, the widget hierarchy of the hello world application
(created in previous chapter) is as specified in the following diagram
• MyApp is the user created widget and it is build using the Flutter native
widget, MaterialApp.
• MaterialApp has a home property to specify the user interface of the
home page, which is again a user created widget, MyHomePage.
• MyHomePage is build using another flutter native widget, Scaffold
• Scaffold has two properties – body and appBar
• body is used to specify its main user interface and appBar is used to
specify its header user interface
• Header UI is build using flutter native widget, AppBar and Body UI is build
using Center widget.
• The Center widget has a property, Child, which refers the actual content
and it is build using Text widget
Architecture d’une application Mobile Flutter : Widget

import 'package:flutter/material.dart';

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

class MyApp extends StatelessWidget {


@override
Widget build(BuildContext context) {
return (MaterialApp(
home: Scaffold(
appBar: AppBar(title: Text('First
App'),backgroundColor: Colors.orange,),
body: Center(
child: Text(
'Hello',style: TextStyle(fontSize: 30),
textAlign: TextAlign.center,
)),
),
));
}
}
Installation et configuration : Télécharger Flutter SDK

https://flutter.dev/docs/get-started/install/windows
Installation et configuration : Variable d’environnement Path
Exécuter la commande : flutter doctor

C:\>flutter doctor
Doctor summary (to see all details, run flutter doctor -v):
[√] Flutter (Channel stable, v1.12.13+hotfix.8, on Microsoft
Windows [version 10.0.18362.657], locale fr-MA)

[√] Android Studio (version 3.3)


[√] IntelliJ IDEA Ultimate Edition (version 2018.2)
[!] VS Code (version 1.41.1)
X Flutter extension not installed; install from
https://marketplace.visualstudio.com/items?itemName=Dart-Code.flutter
[√] Connected device (1 available)

! Doctor found issues in 1 category.

C:\>
Exécuter la commande : flutter doctor

C:\Tools\flutter_windows_v1.12.13+hotfix.8-stable\flutter\bin\flutter.bat doctor --verbose


[√] Flutter (Channel stable, v1.12.13+hotfix.8, on Microsoft Windows [version 10.0.18362.592], locale fr-MA)
• Flutter version 1.12.13+hotfix.8 at C:\Tools\flutter_windows_v1.12.13+hotfix.8-stable\flutter
• Framework revision 0b8abb4724 (6 days ago), 2020-02-11 11:44:36 -0800
• Engine revision e1e6ced81d
• Dart version 2.7.0
[√] Android toolchain - develop for Android devices (Android SDK version 28.0.3)
• Android SDK at C:\Users\med\AppData\Local\Android\Sdk
• Android NDK location not configured (optional; useful for native profiling support)
• Platform android-28, build-tools 28.0.3
• ANDROID_HOME = C:\Users\med\AppData\Local\Android\Sdk
• Java binary at: C:\Tools\Android\Android Studio\jre\bin\java
• Java version OpenJDK Runtime Environment (build 1.8.0_152-release-1248-b01)
• All Android licenses accepted.
[!] Android Studio (version 3.3)
• Android Studio at C:\Tools\Android\Android Studio
X Flutter plugin not installed; this adds Flutter specific functionality.
X Dart plugin not installed; this adds Dart specific functionality.
• Java version OpenJDK Runtime Environment (build 1.8.0_152-release-1248-b01)
[√] IntelliJ IDEA Ultimate Edition (version 2018.2)
• IntelliJ at C:\Program Files\JetBrains\IntelliJ IDEA 2018.2.1
• Flutter plugin version 31.3.2
• Dart plugin version 182.3911.37
[!] VS Code (version 1.41.1)
• VS Code at C:\Users\med\AppData\Local\Programs\Microsoft VS Code
X Flutter extension not installed; install from
https://marketplace.visualstudio.com/items?itemName=Dart-Code.flutter
[!] Connected device
! No devices available
! Doctor found issues in 3 categories.
Process finished with exit code 0
Autres outils à installer
• Pour Android • Install the Flutter and Dart plugins
• To install these:
• Android Studio
• Start Android Studio.
• Android SDK (API 28) • Open plugin preferences (Preferences
> Plugins on macOS, File > Settings >
Plugins on Windows & Linux).
• Install Android Studio
• Select Marketplace, select the Flutter
• Android Studio offers a complete, integrated IDE experience for plugin and click Install.
Flutter. • Click Yes when prompted to install the
• Android Studio, version 3.0 or later Dart plugin.
• Click Restart when prompted.
• Alternatively, you can also use IntelliJ:

• IntelliJ IDEA Community, version 2017.1 or later

• IntelliJ IDEA Ultimate, version 2017.1 or later


Première Application Flutter : flutter create my_app
C:\flutter_projects>flutter create flutter_mobile_app
Recreating project flutter_mobile_app...
Wrote 3 files.

All done!
[√] Flutter: is fully installed. (Channel stable, v1.12.13+hotfix.8, on Microsoft Windows [version
10.0.18362.657], locale fr-MA)
[√] Android toolchain - develop for Android devices: is fully installed. (Android SDK version 28.0.3)
[√] Android Studio: is fully installed. (version 3.3)
[√] IntelliJ IDEA Ultimate Edition: is fully installed. (version 2018.2)
[!] VS Code: is partially installed; more components are available. (version 1.41.1)
[√] Connected device: is fully installed. (1 available)

Run "flutter doctor" for information about installing additional components.

In order to run your application, type:

$ cd flutter_mobile_app
$ flutter run

Your application code is in flutter_mobile_app\lib\main.dart.

C:\flutter_projects>
Exécuter l’application
C:\flutter_projects>flutter devices
1 connected device:
Android SDK built for x86 • emulator-5554 • android-x86 •
Android 8.1.0 (API 27) (emulator)

C:\flutter_projects>cd flutter_mobile_app

C:\flutter_projects\flutter_mobile_app>flutter run

Using hardware rendering with device Android SDK built for x86. If you get
graphics artifacts, consider enabling
software rendering with "--enable-software-rendering".
Launching lib\main.dart on Android SDK built for x86 in debug mode...
Running Gradle task 'assembleDebug'...
Running Gradle task 'assembleDebug'... Done 65,5s
√ Built build\app\outputs\apk\debug\app-debug.apk.
Installing build\app\outputs\apk\app.apk... 5,7s
...
🔥 To hot reload changes while running, press "r". To hot restart (and rebuild
state), press "R".
An Observatory debugger and profiler on Android SDK built for x86 is available
at:
http://127.0.0.1:61179/qro3j0dqa44=/
For a more detailed help message, press "h". To detach, press "d"; to quit,
First App
import 'package:flutter/material.dart';

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

class MyApp extends StatelessWidget {


@override
Widget build(BuildContext context) {
return (MaterialApp(
home: Center(
child: Text(
'Hello',
textAlign: TextAlign.center,
)),
));
}
}
First App : Scaffold Wiget

import 'package:flutter/material.dart';

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

class MyApp extends StatelessWidget {


@override
Widget build(BuildContext context) {
return (MaterialApp(
home: Scaffold(
appBar: AppBar(title: Text('First App'),backgroundColor: Colors.orange,),
body: Center(
child: Text(
'Hello',style: TextStyle(fontSize: 30),
textAlign: TextAlign.center,
)),
),
));
}
}
First App : Scaffold Wiget

import 'package:flutter/material.dart';

void main() => runApp(MaterialApp(


home: MyApp(),
));

class MyApp extends StatelessWidget {


// This widget is the root of your application.
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: Text('First App'),backgroundColor: Colors.orange,),
body: Center(
child: Text(
'Hello',style: TextStyle(fontSize: 30),
textAlign: TextAlign.center,
)),
);
}
}
DART :
DART
DART
DART
DART : Parsing a JSON String
DART : Interface, Imlémentation
Widget Statless et Statfull External
Input Data
• Un Stateless Widget est un widget qui ne dépend
Le rendu est généré
pas d’autre chose que de ses propres informations Statless Widget - Quand les données externes
qui lui sont fournies au moment de son build (par changent

son parent). Aucun événement utilisateur ne


Renders UI
relancera le build d’un stateless widget

• Le Stateful Widget. Est un widget qui a un état


représenté par ses “données internes” qui External
Input Data
changeront au cours du cycle de vie de ce widget.
Le rendu est généré
Les données incluses dans ce type de widget Quand :
Statful Widget - Les données externes changent
forment un ensemble que l’on nomme “State” . - Ou son état interne change
Quand les données du State change, le rendu du
Internal State
widget est regénéré.

Renders UI
Application
First App : Drawer
import 'package:flutter/material.dart’;
import './quiz.dart’;
import './weather.dart';
void main() => runApp(MaterialApp(
home: MyApp(),
));
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('First App'),
backgroundColor: Colors.orange,
),
body: Center(
child: Text(
'Hello',
style: TextStyle(fontSize: 30),
textAlign: TextAlign.center,
)),
drawer: Drawer()
);
}
}
drawer: Drawer(
child: ListView(
First App : Drawer children: <Widget>[
new DrawerHeader(
child: Center(
child: CircleAvatar(
radius: 50,backgroundImage: NetworkImage('https://…/profile.png'),
),
),
decoration: BoxDecoration(
gradient: LinearGradient(colors: [Colors.orange, Colors.white])),
),
ListTile(
title: Text(
'Quiz', style: TextStyle(fontSize: 18),
),
trailing: Icon(Icons.arrow_right),
onTap: () {
Navigator.of(context).pop();
Navigator.push(
context, MaterialPageRoute(builder: (context) => Quiz()));
}),
ListTile(
title: Text(
'Weather',style: TextStyle(fontSize: 18),
),
trailing: Icon(Icons.arrow_right),
onTap: () {
Navigator.of(context).pop();
Navigator.push(context, MaterialPageRoute(builder: (context) => Weather()));
})
],
),
),
);
}
First App : Drawer

import 'package:flutter/material.dart';
class Quiz extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: Text('Quiz'),backgroundColor: Colors.orange,),
body: Center(child: Text('Quiz',style: TextStyle(fontSize: 22),)),
);
}
}

import 'package:flutter/material.dart';
class Weather extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: Text('Weather'),backgroundColor: Colors.orange,),
body: Center(child: Text('Weather',style: TextStyle(fontSize: 22),)),
);
}
}
main.dart

Exemple de Stateless Widget


onTap: () {
Navigator.of(context).pop();
Navigator.push(context,
MaterialPageRoute(builder: (context) => Weather(5)));
Weather.dart })

import 'package:flutter/material.dart';
class Weather extends StatelessWidget {
int counter;
Weather(this.counter);
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: Text('Weather'),backgroundColor: Colors.orange,),
body: Center(
child: Column(
children: <Widget>[
Text('Counter=$counter', style: TextStyle(fontSize: 22),),
RaisedButton(child: Text('Add'),color: Colors.blue,onPressed: (){++counter;},)
],),
),
);
}
}
Exemple de Stateful Widget main.dart
onTap: () {
quiz.dart Navigator.of(context).pop();
import 'package:flutter/material.dart'; Navigator.push(
class Quiz extends StatefulWidget { context, MaterialPageRoute(builder: (context) => Quiz(5)));
int counter; }),
Quiz(this.counter);

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

class _QuizState extends State<Quiz> {


@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('Quiz'),
backgroundColor: Colors.orange,
),
body: Center(
child: Column(
children: <Widget>[
Text('Counter=${widget.counter}', style: TextStyle(fontSize: 22),),
RaisedButton(child: Text('Add'),color: Colors.blue,
onPressed: (){
setState(() {
++widget.counter;
}
);;},)
],),
),
);
}
}
Quiz Page
quiz.dart
import 'package:flutter/material.dart';
class Quiz extends StatefulWidget {
int counter;
Quiz(this.counter);
@override
_QuizState createState() => _QuizState();
}

class _QuizState extends State<Quiz> {


int currentQuestion=0;
int score=0;
final quiz=[
{'title':'Question 1','answers':[
{'answer':'Answer 11', 'correct':false},
{'answer':'Answer 12', 'correct':false},
{'answer':'Answer 13', 'correct':true},
]},{'title':'Question 2','answers':[
{'answer':'Answer 21', 'correct':false},
{'answer':'Answer 22', 'correct':true},
{'answer':'Answer 23', 'correct':false},
]},
];
Quiz Page
quiz.dart
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('Quiz'),
backgroundColor: Colors.orange,
),
body:
(this.currentQuestion>=quiz.length)?
Center(child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Text('Score : ${(score/quiz.length*100).round()} %',style:
TextStyle(color: Colors.deepOrangeAccent,fontSize: 22)),
RaisedButton(
color: Colors.deepOrangeAccent,
onPressed: (){
setState((){
currentQuestion=0;
score=0;
});
},
child: Text('Restart ...',style: TextStyle(color:
Colors.white,fontSize: 22),
))
]
))
Quiz Page
quiz.dart
: ListView(
children: <Widget>[
ListTile(
title: Center(child: Text('Question : ${currentQuestion+1}/${quiz.length}',style:
TextStyle(fontSize: 22,fontWeight: FontWeight.bold, color: Colors.deepOrangeAccent))) ,
),
ListTile(
title: Text ('${quiz[currentQuestion]['title']} ?',style: TextStyle(fontSize:
22,fontWeight: FontWeight.bold),),),
...(quiz[currentQuestion]['answers'] as List<Map<String,Object>>).map((answer){
return Padding(
padding: const EdgeInsets.all(8.0),
child: RaisedButton(
color: Colors.deepOrangeAccent,
onPressed: (){
setState(() {
if(answer['correct']==true) ++score;
++this.currentQuestion;
});
},
child:Container(
child: Align( alignment: Alignment.centerLeft,
child: Text(answer['answer'],style: TextStyle(color: Colors.white,fontSize: 22,fontWeight:
FontWeight.bold),)),padding: EdgeInsets.all(10),),
),
);
})
],
),
);
}}
Weather Page weather-form.dart
import 'package:flutter/material.dart’;
import './weather.dart’;

class WeatherForm extends StatefulWidget {


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

class _WeatherFormState extends State<WeatherForm> {


String city;
TextEditingController cityEditingController=new TextEditingController();
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: Text('${city}'),backgroundColor:
Colors.deepOrangeAccent,),
body: Column(
children: <Widget>[
Container(
child: Padding(
padding: const EdgeInsets.all(12.0),
child: TextField(
decoration: InputDecoration(hintText: 'Tape a City..'),
controller: cityEditingController,
onChanged: (String str){
setState((){
city=str;
});
},
Weather Page
weather-form.dart
onSubmitted: (String str){
Navigator.of(context).push(MaterialPageRoute(builder: (context)=>Weather(city)));
cityEditingController.text="";
},
),
),
),
Container(
width: double.infinity,
padding: EdgeInsets.all(10),
child: RaisedButton(
child: Text('Get Weather'),
textColor:Colors.white ,
onPressed: (){
Navigator.of(context).push(MaterialPageRoute(
builder: (context)=>Weather(city)));
cityEditingController.text="";
},
color: Colors.deepOrangeAccent,
),
)
],
),
);
}
}
Weather Page dependencies:
weather.dart flutter:
sdk: flutter
import 'package:flutter/material.dart'; http: ^0.12.0+4
import 'package:http/http.dart' as http; intl: ^0.15.8
import 'dart:async';
import 'dart:convert';
import 'package:intl/intl.dart';
class Weather extends StatefulWidget {
String city;
Weather(this.city);
@override
_WeatherState createState() => _WeatherState();
}

class _WeatherState extends State<Weather> {

List<dynamic> weatherData;
getData(url){
http.get(
Uri.encodeFull(url), headers: {'accept':'application/json'}
).then((resp){
setState((){
weatherData=json.decode(resp.body)['list'];
});
}).catchError((err){
print(err);
});
}
Weather Page
weather.dart
@override
void initState() {
super.initState();
String
url='http://openweathermap.org/data/2.5/forecast?q=${this.widget.city}&appid=b6907d2
89e10d714a6e88b30761fae22';
print(url);
this.getData(url);
}
Weather Page
weather.dart

@override
Widget build(BuildContext context) {
List<String> listData=getListData();
return Scaffold(
appBar: AppBar(title: Text('${widget.city}'),backgroundColor:
Colors.orange,),
body:
(weatherData==null)?Center(child: CircularProgressIndicator()):
ListView.builder(
itemCount: weatherData==null?0:weatherData.length,
itemBuilder: (context,index){
return Card(
// List ITEM …
);
})

);
}
}
pubspec.yaml
Weather Page assets:
- images/profile.jpg
weather.dart
- images/clear.png
Card( - images/clouds.png
color: Colors.deepOrangeAccent, - images/rain.png
child: Padding( - images/snow.png
padding: const EdgeInsets.all(12.0),
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: <Widget>[
Row(
children: <Widget>[
CircleAvatar(
backgroundImage: AssetImage('images/${weatherData[index]['weather'][0]['main'].toLowerCase()}.png'),
),
Padding(
padding: const EdgeInsets.only(left: 10),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
Text("${new DateFormat('E dd/MM/yyyy').format(DateTime.fromMicrosecondsSinceEpoch(weatherData[index]['dt']*1000000))}",
style: TextStyle(fontSize: 16,color: Colors.white,fontWeight:FontWeight.bold)),
Text("${new DateFormat('HH:mm').format(DateTime.fromMicrosecondsSinceEpoch(weatherData[index]['dt']*1000000))} |
${weatherData[index]['weather'][0]['main']}",style: TextStyle(fontSize: 20,color: Colors.white,fontWeight:FontWeight.bold)),
],
),
),
],
),
Text("${weatherData[index]['main']['temp'].round()} °C", style: TextStyle(fontSize: 20,color:
Colors.white,fontWeight:FontWeight.bold),),
],
),
),
);
Gallery Page
Weather Page
class _GalleryState extends State<Gallery> {
String keyword;
gallery.dart @override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
import 'package:flutter/material.dart';
backgroundColor: Colors.deepOrange, title: Text('${keyword}')
import 'package:http/http.dart' as http;
),
import 'dart:convert';
body: Padding(
class Gallery extends StatefulWidget {
padding: const EdgeInsets.all(8.0),
@override
child: Column(
_GalleryState createState() =>
children: <Widget>[
_GalleryState();
TextField(
}
decoration: InputDecoration(hintText: 'Key word'),
onChanged: (value){
setState((){ this.keyword=value; });
},
onSubmitted: (value){
Navigator.of(context).push(MaterialPageRoute(builder:(context)=>GalleryData(value)));
},
),
Container(
width: double.infinity,
child: RaisedButton(
onPressed: (){
Navigator.of(context).push(MaterialPageRoute(builder:(context)=>GalleryData(this.keyword)));
}, color: Colors.deepOrange,textColor: Colors.white,child: Text('Get Data'),
),
), ], ), ),);} }
Weather Page class GalleryData extends StatefulWidget {
String keyWord;
gallery.dart GalleryData(this.keyWord);
@override
_GalleryDataState createState() => _GalleryDataState();
}

class _GalleryDataState extends State<GalleryData> {


List<dynamic> data;
int currentPage=1;int pageSize=10; int totalPages=0;
ScrollController _scrollController=new ScrollController();
dynamic dataGallery;
List<dynamic> hits=new List();
getData(url){
http.get(url).then((resp){
setState(() {
dataGallery=json.decode(resp.body);
hits.addAll(dataGallery['hits']);
if(dataGallery['totalHits']%this.pageSize==0)
this.totalPages=dataGallery['totalHits']~/this.pageSize;
else this.totalPages=1+(dataGallery['totalHits']/this.pageSize).floor();
});
}).catchError((err){
print(err);
});
}
Weather Page @override
void initState() {
gallery.dart super.initState();this.loadData();
this._scrollController.addListener((){
if(_scrollController.position.pixels==_scrollController.position.maxScrollExtent){
if(currentPage<totalPages){
++currentPage;
this.loadData();
}
}
});
}
@override void dispose() {
// TODO: implement dispose
super.dispose();
_scrollController.dispose();
}

void loadData(){
String url="https://pixabay.com/api/?key=5832566-
81dc7429a63c86e3b707d0429&q=${widget.keyWord}&page=$currentPage&per_page=$pageSize";
print(url);
this.getData(url);
}
Camera Page
Camera Page import 'dart:io';
import 'package:flutter/material.dart';
camera.dart import 'package:image_picker/image_picker.dart';
import 'package:image_cropper/image_cropper.dart';
import 'package:firebase_ml_vision/firebase_ml_vision.dart';
class CameraPage extends StatefulWidget {
@override
_CameraPageState createState() => _CameraPageState();
}
class _CameraPageState extends State<CameraPage> {
File imageFile; VisionText visionTextOCR;
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title:Text('Camera'),backgroundColor: Colors.deepOrange,),
body: Container(
child: Center(
child: Column( mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: <Widget>[
Container(
width: double.infinity, padding: EdgeInsets.all(10),
child: MaterialButton(
color: Colors.blue,
onPressed: (){ openDialog(context);},
child: Text('Pick Image',style: TextStyle(color: Colors.white,fontSize: 22),),
),
),
Camera Page
Container(
height: 200,
width: double.infinity,
camera.dart padding: const EdgeInsets.all(8.0),
child:
SingleChildScrollView(child: Text('${visionTextOCR==null?'':visionTextOCR.text}', )),
),

Padding(
padding: const EdgeInsets.all(8.0),
child: Container(
padding: EdgeInsets.all(20),
width: double.infinity,
height: 400,
decoration: BoxDecoration(
border: Border.all(color: Colors.deepOrangeAccent,width: 1),
borderRadius: BorderRadius.circular(10),
image: DecorationImage(
fit: BoxFit.cover,
image: (imageFile!=null)?FileImage(imageFile,):AssetImage('images/profile.jpg')),
)
),
),

],
),
),
),
);
}
}
Camera Page
Future<VisionText> textRecognoition(File imageFile){
final FirebaseVisionImage visionImage = FirebaseVisionImage.fromFile(imageFile);
final TextRecognizer textRecognizer = FirebaseVision.instance.textRecognizer();
camera.dart final Future <VisionText> visionText = textRecognizer.processImage(visionImage);
return visionText;
}
Future<void> openDialog(BuildContext context){
return showDialog(context: context,builder: (BuildContext context){
return AlertDialog(
title: Text('Make a Choice'),
actions: <Widget>[
FlatButton(
child: Text('Gallery'),
onPressed: () async{
Navigator.of(context).pop();
var file=await ImagePicker.pickImage(source: ImageSource.gallery);
File croppedFile = await ImageCropper.cropImage(sourcePath: file.path,);
VisionText visionText=await textRecognoition(croppedFile);
setState(() {imageFile=file;visionTextOCR=visionText;});
},
),
FlatButton(
child: Text('Camera'),
onPressed: () async{
Navigator.of(context).pop();
var file=await ImagePicker.pickImage(source: ImageSource.camera,maxWidth: 400, maxHeight: 400);
File croppedFile = await ImageCropper.cropImage(sourcePath: file.path);
VisionText visionText=await textRecognoition(croppedFile);
print(visionText.text);
setState(() { imageFile=file; visionTextOCR=visionText; });
},
)
],
);
});
}
Camera Page
camera.dart

build.gradle : App Level dependencies


dependencies { dependencies:
classpath 'com.google.gms:google-services:4.2.0' image_picker:
} image_cropper:
firebase_ml_vision:
build.gradle: src level
dependencies {
implementation 'com.google.firebase:firebase-core:16.0.9'
}
apply plugin: 'com.google.gms.google-services'

androidManifest.xml
<application>
<activity
android:name="com.yalantis.ucrop.UCropActivity"
android:screenOrientation="portrait"
android:theme="@style/Theme.AppCompat.Light.NoActionBar"/>
</application>
Camera Page
camera.dart

Télécharger google-services.json
Flutter
class _MyHomePageState extends State<MyHomePage> {
int _counter = 0;

Structure du Projet void _incrementCounter() {


setState(() {
_counter++;
class MyHomePage extends StatefulWidget { });
}
MyHomePage({Key key, this.title}) : super(key:
@override
key); Widget build(BuildContext context) {
final String title;
@override return Scaffold(
_MyHomePageState createState() => appBar: AppBar(
_MyHomePageState(); title: Text(widget.title),
),
}
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Text(
'You have pushed the button this many times:',
),
Text(
'$_counter',
style: Theme.of(context).textTheme.display1,
),
],
),
),
floatingActionButton: FloatingActionButton(
onPressed: _incrementCounter,
tooltip: 'Increment', child: Icon(Icons.add),
),
);
}
}
Flutter
main.dart

import 'package:flutter/material.dart';

import 'Quiz.dart';

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

class MyApp extends StatelessWidget{


@override
Widget build(BuildContext context) {
// TODO: implement build
return MaterialApp(
home: Scaffold(
backgroundColor: Colors.white,
appBar: AppBar(title: Text('Quiz App'),backgroundColor:
Colors.orangeAccent,),
body: Center(
child: Quiz(),
),
),
);
}
}
Flutter
Quiz.dart

class QuizState extends State<Quiz> {


int currentQuestionIndex = 0;
int score = 0;
final quiz = [
{
'question': 'Q 1 - Which of the following is correct about Java 8 lambda expression ?',
'answers': [
{'answer': 'A - Using lambda expression, you can refer to final variable or effectively final
variable (which is assigned only once)', 'correct': false},
{'answer': 'B - Lambda expression throws a compilation error, if a variable is assigned a value the
second time ?', 'correct': false},
{'answer': 'C - Both of the above.', 'correct': true},
{'answer': 'D - None of the above.', 'correct': false},
],
},
{
'question': 'Q 8 - Which of the following is the correct lambda expression which add two numbers and
return their sum?',
'answers': [
{'answer': 'A - (int a, int b) -> { return a + b;};', 'correct': false},
{'answer': 'B - (a, b) -> {return a + b;};', 'correct': false},
{'answer': 'C - Both of the above.', 'correct': true},
{'answer': 'D - None of the above.', 'correct': false},
],
}
];
Quiz.dart
@override
Widget build(BuildContext context) {
return (currentQuestionIndex >= quiz.length)
? Container(
padding: EdgeInsets.all(20),
child: Column(children: <Widget>[
Text('Results: Your score is ${score/quiz.length*100} %', style: TextStyle(fontSize: 20),),
FlatButton(
child: Text('Restart', style: TextStyle(fontSize: 20, color: Colors.blue)),
onPressed: resetQuiz,
)
]))
: SingleChildScrollView (padding: EdgeInsets.all(10),
child: Column(
children: <Widget>[
Text((currentQuestionIndex + 1).toString() +"/" + quiz.length.toString(),style: TextStyle(fontSize: 22)),
Container(
width: double.infinity, padding: EdgeInsets.all(10),margin: EdgeInsets.all(10),
child: Text(
quiz[currentQuestionIndex]['question'],style: TextStyle(fontSize: 20), textAlign: TextAlign.center,
),
),
...(quiz[currentQuestionIndex]['answers'] as List<Map<String, Object>>) .map((answer) {
return Container(padding: EdgeInsets.all(10),
child: RaisedButton(
child: Align(alignment: Alignment.centerLeft,
child: Text(answer['answer'],style: TextStyle(fontSize: 16),textAlign: TextAlign.left,),
),
onPressed: () => handleAnswer(answer),color: Colors.orange,textColor: Colors.white,padding: EdgeInsets.all(10)
),
);
}),
],
));
}
Quiz.dart
void handleAnswer(answser) {
print('Answer of question $currentQuestionIndex');
setState(() {
++currentQuestionIndex;
});
if (answser['correct'] == true) ++score;
}

void resetQuiz() {
setState(() {
currentQuestionIndex = 0;
score=0;
});
}
}
Décomposition du Widget Quiz en 4 widgets : Quiz, Question, Answer et Score
Quiz.dart
import 'package:demo/question.dart’;
import 'package:demo/score.dart';import 'package:flutter/material.dart';import 'answer.dart';
class Quiz extends StatefulWidget {
@override
State<StatefulWidget> createState() {
// TODO: implement createState
return QuizState(); Question
}
}
class QuizState extends State<Quiz> {
int currentQuestionIndex = 0; int score = 0; final quiz = [ ... ]; Answer
@override
Widget build(BuildContext context) { void handleAnswer(answser) {
return (currentQuestionIndex >= quiz.length) print('Answer of question
? Score(score, resetQuiz, quiz.length) $currentQuestionIndex');
: SingleChildScrollView ( setState(() {
padding: EdgeInsets.all(10), ++currentQuestionIndex;
child: Column( });
children: <Widget>[ if (answser['correct'] == true)
Question(quiz[currentQuestionIndex]['question'], ++score;
currentQuestionIndex, quiz.length), }
...(quiz[currentQuestionIndex]['answers']
as List<Map<String, Object>>) void resetQuiz() {
.map((answer) { setState(() {
return Answer(answer, handleAnswer); currentQuestionIndex = 0;
}), score = 0;
], });
)); }
} }
Décomposition du Widget Quiz en 4 widgets : Quiz, Question, Answer et Score
Question.dart
import 'package:flutter/material.dart';
class Question extends StatelessWidget {
int _currentQuestionIndex; String _question; int _numberOfQuestions;
Question(this._question,this._currentQuestionIndex, this._numberOfQuestions);
@override
Widget build(BuildContext context) { Question
return Container(
child: Column(
children: <Widget>[ Answer
Text(
(_currentQuestionIndex + 1).toString() +"/" +_numberOfQuestions.toString(),
style: TextStyle(fontSize: 22)),
Container(
width: double.infinity, padding: EdgeInsets.all(10), margin: EdgeInsets.all(10),
child: Text(
_question,
style: TextStyle(fontSize: 20), textAlign: TextAlign.center,
),
),
],
),
);
}
}
Décomposition du Widget Quiz en 4 widgets : Quiz, Question, Answer et Score
Answer.dart
import 'package:flutter/material.dart';
class Answer extends StatelessWidget {
Map<String,Object> _answer;
Function _handleAnswer;
Answer(this._answer,this._handleAnswer);
@override Question
Widget build(BuildContext context) {
return Container(padding: EdgeInsets.all(10),
child: RaisedButton( Answer
child: Align(alignment: Alignment.centerLeft,
child: Text(
_answer['answer'],
style: TextStyle(fontSize: 16),textAlign: TextAlign.left,
),
),
onPressed: () => _handleAnswer(_answer),
color: Colors.orange,
textColor: Colors.white,
padding: EdgeInsets.all(10)
),
);
}
}
Décomposition du Widget Quiz en 4 widgets : Quiz, Question, Answer et Score
Score.dart
import 'package:flutter/material.dart';
class Score extends StatelessWidget {
int _score;
int _numberOfQuestions;
Function _resetQuiz;
Score(this._score,this._resetQuiz,this._numberOfQuestions);
@override
Widget build(BuildContext context) { Score
return Container(
padding: EdgeInsets.all(20),
child: Column(children: <Widget>[
Text(
'Results: Your score is ${_score/_numberOfQuestions*100} %',
style: TextStyle(fontSize: 20),
),
FlatButton(
child: Text('Restart',
style: TextStyle(fontSize: 20, color: Colors.blue)),
onPressed: _resetQuiz,
)
]));
}
}
Unsing Tabs in Flutter
main.dart
import 'package:demo/weather.dart';import 'package:flutter/material.dart’; import 'Quiz.dart';
void main()=>runApp(MyApp());
class MyApp extends StatelessWidget{
@override
Widget build(BuildContext context) {
// TODO: implement build
return MaterialApp(
home: DefaultTabController(
length: 2,
child: Scaffold(
appBar: AppBar(
bottom: TabBar(
tabs: [
Tab(
icon: Icon(Icons.directions_car),
),
Tab(
icon: Icon(Icons.transit_enterexit),
),
]
),
title: Text('Tab Demo'),
),
body: TabBarView(
children: [ Quiz(), Weather() ]),

)
),
);
}
}
Unsing Tabs in Flutter

weather.dart
import 'package:flutter/material.dart';
class Weather extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Container(alignment: Alignment.center,
child: Text('Weather'),
);
}
}

Vous aimerez peut-être aussi