Développement Mobile Cross Platform Avec FLUTTER [PDF]

  • 0 0 0
  • Gefällt Ihnen dieses papier und der download? Sie können Ihre eigene PDF-Datei in wenigen Minuten kostenlos online veröffentlichen! Anmelden
Datei wird geladen, bitte warten...
Zitiervorschau

Développement Mobile Native Cross Platform : Flutter Flutter Approach

Native ARM Binary Code

Flutter Widgets Cupertino Material Design

Platform Channels

Mohamed Youssfi Laboratoire Signaux Systèmes Distribués et Intelligence Artificielle (SSDIA) ENSET, Université Hassan II Casablanca, Maroc Email : [email protected] 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, qui permet de créer des applications natives Android et/ou IOS. En utilisant le langage de programmation DART • La version 1.0 de Flutter a été annoncé le 4 décembre 2018. • Dart est un langage de programmation développé par la 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

Flutter Approach

Native ARM Binary Code

Flutter Widgets Cupertino Material Design

Platform Channels

Développement Mobile Cross Platform Flutter Approach

Hybrid Approach : IONIC, PhoneGap, Mobile First

Web View

HTML CSS Java Script

Native ARM Binary Code



Native Cross Plaform Approach : React Native

Java Script (Reactive)

Bridge: Java Script Bridge (Reactive)

OEM Widgets (Capertini, Materal Design)





Hybrid • • •

Flutter Widgets Cupertino Material Design

Platform Channels

Approach (IONIC): Utilise le moteur de rendu HTML, CSS du Web View pour la logique présentation 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) React Native : • Utilise ses proposes Composants pour la logique présentation, qui seront mappé en composant OEM Natif de l’appareil Mobile • Utilise Java Script pour les traitements avec React JS Comme Framework • Utilise un Bridge Java Script pour accéder aux fonctionnalités Natives Flutter : • Utilise ses propres composants natifs pour la logique présentation. Flutter utilise son propore 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 • Android Studio

• Android SDK (API 28)

• Install Android Studio • Android Studio offers a complete, integrated IDE experience for Flutter. • Android Studio, version 3.0 or later • Alternatively, you can also use IntelliJ:

• IntelliJ IDEA Community, version 2017.1 or later • IntelliJ IDEA Ultimate, version 2017.1 or later

• Install the Flutter and Dart plugins • To install these: • Start Android Studio. • Open plugin preferences (Preferences > Plugins on macOS, File > Settings > Plugins on Windows & Linux). • Select Marketplace, select the Flutter plugin and click Install. • Click Yes when prompted to install the Dart plugin. • Click Restart when prompted.

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 pas d’autre chose que de ses propres informations

Statless Widget

qui lui sont fournies au moment de son build (par son parent). Aucun événement utilisateur ne relancera le build d’un stateless widget

Le rendu est généré - Quand les données externes changent

Renders UI

• Le Stateful Widget. Est un widget qui a un état représenté par ses “données internes” qui changeront au cours du cycle de vie de ce widget. Les données incluses dans ce type de widget

forment un ensemble que l’on nomme “State” . Quand les données du State change, le rendu du widget est regénéré.

External Input Data Statful Widget

Internal State

Renders UI

Le rendu est généré Quand : - Les données externes changent - Ou son état interne change

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() ); } }

First App : Drawer

drawer: Drawer( child: ListView( children: [ 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 Weather.dart

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

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: [ Text('Counter=$counter', style: TextStyle(fontSize: 22),), RaisedButton(child: Text('Add'),color: Colors.blue,onPressed: (){++counter;},) ],), ), ); } }

Exemple de Stateful Widget quiz.dart import 'package:flutter/material.dart'; class Quiz extends StatefulWidget { int counter; Quiz(this.counter);

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

@override _QuizState createState() => _QuizState(); } class _QuizState extends State { @override Widget build(BuildContext context) { return Scaffold( appBar: AppBar( title: Text('Quiz'), backgroundColor: Colors.orange, ), body: Center( child: Column( children: [ 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 { 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: [ 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: [ 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((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 { String city; TextEditingController cityEditingController=new TextEditingController(); @override Widget build(BuildContext context) { return Scaffold( appBar: AppBar(title: Text('${city}'),backgroundColor: Colors.deepOrangeAccent,), body: Column( children: [ 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 weather.dart import 'package:flutter/material.dart'; import 'package:http/http.dart' as http; import 'dart:async'; import 'dart:convert'; import 'package:intl/intl.dart'; class Weather extends StatefulWidget { String city; Weather(this.city); @override _WeatherState createState() => _WeatherState(); }

dependencies: flutter: sdk: flutter http: ^0.12.0+4 intl: ^0.15.8

class _WeatherState extends State {

List 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 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 … ); }) ); } }

Weather Page weather.dart Card(

pubspec.yaml assets: - images/profile.jpg - images/clear.png - images/clouds.png - images/rain.png - images/snow.png

color: Colors.deepOrangeAccent, child: Padding( padding: const EdgeInsets.all(12.0), child: Row( mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ Row( children: [ CircleAvatar( backgroundImage: AssetImage('images/${weatherData[index]['weather'][0]['main'].toLowerCase()}.png'), ), Padding( padding: const EdgeInsets.only(left: 10), child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ 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 gallery.dart

import 'package:flutter/material.dart'; import 'package:http/http.dart' as http; import 'dart:convert'; class Gallery extends StatefulWidget { @override _GalleryState createState() => _GalleryState(); }

class _GalleryState extends State { String keyword; @override Widget build(BuildContext context) { return Scaffold( appBar: AppBar( backgroundColor: Colors.deepOrange, title: Text('${keyword}') ), body: Padding( padding: const EdgeInsets.all(8.0), child: Column( children: [ 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; GalleryData(this.keyWord); @override _GalleryDataState createState() => _GalleryDataState();

gallery.dart

} class _GalleryDataState extends State { List data; int currentPage=1;int pageSize=10; int totalPages=0; ScrollController _scrollController=new ScrollController(); dynamic dataGallery; List 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 gallery.dart

@override void initState() { super.initState();this.loadData(); this._scrollController.addListener((){ if(_scrollController.position.pixels==_scrollController.position.maxScrollExtent){ if(currentPage _CameraPageState(); } class _CameraPageState extends State { 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: [ 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, padding: const EdgeInsets.all(8.0), child: SingleChildScrollView(child: Text('${visionTextOCR==null?'':visionTextOCR.text}', )), ),

camera.dart

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 camera.dart

Future textRecognoition(File imageFile){ final FirebaseVisionImage visionImage = FirebaseVisionImage.fromFile(imageFile); final TextRecognizer textRecognizer = FirebaseVision.instance.textRecognizer(); final Future visionText = textRecognizer.processImage(visionImage); return visionText; } Future openDialog(BuildContext context){ return showDialog(context: context,builder: (BuildContext context){ return AlertDialog( title: Text('Make a Choice'), actions: [ 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 { classpath 'com.google.gms:google-services:4.2.0' }

dependencies: 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



Camera Page camera.dart

Télécharger google-services.json

Flutter

class _MyHomePageState extends State { int _counter = 0;

Structure du Projet

void _incrementCounter() { setState(() { _counter++; }); } @override Widget build(BuildContext context) {

class MyHomePage extends StatefulWidget { MyHomePage({Key key, this.title}) : super(key: key); final String title; @override _MyHomePageState createState() => _MyHomePageState(); }

return Scaffold( appBar: AppBar( title: Text(widget.title), ), body: Center( child: Column( mainAxisAlignment: MainAxisAlignment.center, children: [ 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 { 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: [ 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: [ 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((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 createState() { // TODO: implement createState return QuizState(); Question } } class QuizState extends State { Answer int currentQuestionIndex = 0; int score = 0; final quiz = [ ... ]; @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: [ if (answser['correct'] == true) Question(quiz[currentQuestionIndex]['question'], ++score; currentQuestionIndex, quiz.length), } ...(quiz[currentQuestionIndex]['answers'] as List) 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) { return Container( child: Column( children: [ 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, ), ), ], ), ); } }

Question

Answer

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 _answer; Function _handleAnswer; Answer(this._answer,this._handleAnswer); @override Widget build(BuildContext context) { 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) ), ); } }

Question

Answer

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) { return Container( padding: EdgeInsets.all(20), child: Column(children: [ 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, ) ])); } }

Score

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'), ); } }