Flutter – Introduction to Layouts Since the core concept of Flutter is Everything is widget, Flutter incorporates a user interface layout functionality into the widgets itself. Flutter provides quite a lot of specially designed widgets like Container, Center, Align, etc., only for the purpose of laying out the user interface. Widgets build by composing other widgets normally use layout widgets. Let use learn the Flutter layout concept in this chapter. Type of Layout Widgets Layout widgets can be grouped into two distinct category based on its child − Widget supporting a single child Widget supporting multiple child Let us learn both type of widgets and its functionality in the upcoming sections. Single Child Widgets In this category, widgets will have only one widget as its child and every widget will have a special layout functionality. For example, Center widget just centers it child widget with respect to its parent widget and Container widget provides complete flexibility to place it child at any given place inside it using different option like padding, decoration, etc., Single child widgets are great options to create high quality widget having single functionality such as button, label, etc., The code to create a simple button using Container widget is as follows − class MyButton extends StatelessWidget { MyButton({Key key}) : super(key: key); @override Widget build(BuildContext context) { return Container( decoration: const BoxDecoration( border: Border( top: BorderSide(width: 1.0, color: Color(0xFFFFFFFFFF)), left: BorderSide(width: 1.0, color: Color(0xFFFFFFFFFF)), right: BorderSide(width: 1.0, color: Color(0xFFFF000000)), bottom: BorderSide(width: 1.0, color: Color(0xFFFF000000)), ), ), child: Container( padding: const EdgeInsets.symmetric(horizontal: 20.0, vertical: 2.0), decoration: const BoxDecoration( border: Border( top: BorderSide(width: 1.0, color: Color(0xFFFFDFDFDF)), left: BorderSide(width: 1.0, color: Color(0xFFFFDFDFDF)), right: BorderSide(width: 1.0, color: Color(0xFFFF7F7F7F)), bottom: BorderSide(width: 1.0, color: Color(0xFFFF7F7F7F)), ), color: Colors.grey, ), child: const Text( ”OK”,textAlign: TextAlign.center, style: TextStyle(color: Colors.black) ), ), ); } } Here, we have used two widgets – a Container widget and a Text widget. The result of the widget is as a custom button as shown below − Let us check some of the most important single child layout widgets provided by Flutter − Padding − Used to arrange its child widget by the given padding. Here, padding can be provided by EdgeInsets class. Align − Align its child widget within itself using the value of alignment property. The value for alignment property can be provided by FractionalOffset class. The FractionalOffset class specifies the offsets in terms of a distance from the top left. Some of the possible values of offsets are as follows − FractionalOffset(1.0, 0.0) represents the top right. FractionalOffset(0.0, 1.0) represents the bottom left. A sample code about offsets is shown below − Center( child: Container( height: 100.0, width: 100.0, color: Colors.yellow, child: Align( alignment: FractionalOffset(0.2, 0.6), child: Container( height: 40.0, width: 40.0, color: Colors.red, ), ), ), ) FittedBox − It scales the child widget and then positions it according to the specified fit. AspectRatio − It attempts to size the child widget to the specified aspect ratio ConstrainedBox Baseline FractinallySizedBox IntrinsicHeight IntrinsicWidth LiimitedBox OffStage OverflowBox SizedBox SizedOverflowBox Transform CustomSingleChildLayout Our hello world application is using material based layout widgets to design the home page. Let us modify our hello world application to build the home page using basic layout widgets as specified below − Container − Generic, single child, box based container widget with alignment, padding, border and margin along with rich styling features. Center − Simple, Single child container widget, which centers its child widget. The modified code of the MyHomePage and MyApp widget is as below − class MyApp extends StatelessWidget { @override Widget build(BuildContext context) { return MyHomePage(title: “Hello World demo app”); } } class MyHomePage extends StatelessWidget { MyHomePage({Key key, this.title}) : super(key: key); final String title; @override Widget build(BuildContext context) { return Container( decoration: BoxDecoration(color: Colors.white,), padding: EdgeInsets.all(25), child: Center( child:Text( ”Hello World”, style: TextStyle( color: Colors.black, letterSpacing: 0.5, fontSize: 20, ), textDirection: TextDirection.ltr, ), ) ); } } Here, Container widget is the top level or root widget. Container is configured using decoration and padding property to layout its content. BoxDecoration has many properties like color, border, etc., to decorate the Container widget and here, color is used to set the color of the container. padding of the Container widget is set by using dgeInsets class, which provides the option to specify the padding value. Center is the child widget of the Container widget. Again, Text is the child of the Center widget. Text is used to show message and Center is used to center the text message with respect to the parent widget, Container. The final result of the code given above is a layout sample as shown below − Multiple Child Widgets In this category, a given widget will have more than one child widgets and the layout of each widget is unique. For example, Row widget allows the laying out of its children in horizontal direction, whereas Column widget allows laying out of its children in vertical direction. By composing Row and Column, widget with any level of complexity can be built. Let us learn some of the frequently used widgets in this section. Row − Allows to arrange its children in a horizontal manner. Column − Allows to arrange its children in a vertical manner. ListView − Allows to arrange its children as list. GridView − Allows to arrange its children as gallery. Expanded − Used to make the children of Row and Column widget to occupy the maximum possible area. Table − Table based widget. Flow − Flow based widget. Stack − Stack based widget. Advanced Layout Application In this section, let us learn how to create a complex user interface of product listing with custom design using both single and multiple child layout widgets. For this purpose, follow the sequence given below − Create a new Flutter application in Android studio, product_layout_app. Replace the main.dart code with folowing code − import ”package:flutter/material.dart void main() => runApp(MyApp()); class MyApp extends StatelessWidget { // This widget is the root of your application. @override Widget
Category: flutter
Flutter – Testing Testing is very important phase in the development life cycle of an application. It ensures that the application is of high quality. Testing requires careful planning and execution. It is also the most time consuming phase of the development. Dart language and Flutter framework provides extensive support for the automated testing of an application. Types of Testing Generally, three types of testing processes are available to completely test an application. They are as follows − Unit Testing Unit testing is the easiest method to test an application. It is based on ensuring the correctness of a piece of code (a function, in general) o a method of a class. But, it does not reflect the real environment and subsequently, is the least option to find the bugs. Widget Testing Widget testing is based on ensuring the correctness of the widget creation, rendering and interaction with other widgets as expected. It goes one step further and provides near real-time environment to find more bugs. Integration Testing Integration testing involves both unit testing and widget testing along with external component of the application like database, web service, etc., It simulates or mocks the real environment to find nearly all bugs, but it is the most complicated process. Flutter provides support for all types of testing. It provides extensive and exclusive support for Widget testing. In this chapter, we will discuss widget testing in detail. Widget Testing Flutter testing framework provides testWidgets method to test widgets. It accepts two arguments − Test description Test code testWidgets(”test description: find a widget”, ”<test code>”); Steps Involved Widget Testing involves three distinct steps − Render the widget in the testing environment. WidgetTester is the class provided by Flutter testing framework to build and renders the widget. pumpWidget method of the WidgetTester class accepts any widget and renders it in the testing environment. testWidgets(”finds a specific instance”, (WidgetTester tester) async { await tester.pumpWidget(MaterialApp( home: Scaffold( body: Text(”Hello”), ), )); }); Finding the widget, which we need to test. Flutter framework provides many options to find the widgets rendered in the testing environment and they are generally called Finders. The most frequently used finders are find.text, find.byKey and find.byWidget. find.text finds the widget that contains the specified text. find.text(”Hello”) find.byKey find the widget by its specific key. find.byKey(”home”) find.byWidget find the widget by its instance variable. find.byWidget(homeWidget) Ensuring the widget works as expected. Flutter framework provides many options to match the widget with the expected widget and they are normally called Matchers. We can use the expect method provided by the testing framework to match the widget, which we found in the second step with our our expected widget by choosing any of the matchers. Some of the important matchers are as follows. findsOneWidget − verifies a single widget is found. expect(find.text(”Hello”), findsOneWidget); findsNothing − verifies no widgets are found expect(find.text(”Hello World”), findsNothing); findsWidgets − verifies more than a single widget is found. expect(find.text(”Save”), findsWidgets); findsNWidgets − verifies N number of widgets are found. expect(find.text(”Save”), findsNWidgets(2)); The complete test code is as follows − testWidgets(”finds hello widget”, (WidgetTester tester) async { await tester.pumpWidget(MaterialApp( home: Scaffold( body: Text(”Hello”), ), )); expect(find.text(”Hello”), findsOneWidget); }); Here, we rendered a MaterialApp widget with text Hello using Text widget in its body. Then, we used find.text to find the widget and then matched it using findsOneWidget. Working Example Let us create a simple flutter application and write a widget test to understand better the steps involved and the concept. Create a new flutter application, flutter_test_app in Android studio. Open widget_test.dart in test folder. It has a sample testing code as given below − testWidgets(”Counter increments smoke test”, (WidgetTester tester) async { // Build our app and trigger a frame. await tester.pumpWidget(MyApp()); // Verify that our counter starts at 0. expect(find.text(”0”), findsOneWidget); expect(find.text(”1”), findsNothing); // Tap the ”+” icon and trigger a frame. await tester.tap(find.byIcon(Icons.add)); await tester.pump(); // Verify that our counter has incremented. expect(find.text(”0”), findsNothing); expect(find.text(”1”), findsOneWidget); }); Here, the test code does the following functionalities − Renders MyApp widget using tester.pumpWidget. Ensures that the counter is initially zero using findsOneWidget and findsNothing matchers. Finds the counter increment button using find.byIcon method. Taps the counter increment button using tester.tap method. Ensures that the counter is increased using findsOneWidget and findsNothing matchers. Let us again tap the counter increment button and then check whether the counter is increased to two. await tester.tap(find.byIcon(Icons.add)); await tester.pump(); expect(find.text(”2”), findsOneWidget); Click Run menu. Click tests in widget_test.dart option. This will run the test and report the result in the result window. Learn online work project make money
Flutter – Writing IOS Specific Code Accessing iOS specific code is similar to that on Android platform except that it uses iOS specific languages – Objective-C or Swift and iOS SDK. Otherwise, the concept is same as that of the Android platform. Let us write the same application as in the previous chapter for iOS platform as well. Let us create a new application in Android Studio (macOS), flutter_browser_ios_app Follow steps 2 – 6 as in previous chapter. Start XCode and click File → Open Choose the xcode project under ios directory of our flutter project. Open AppDelegate.m under Runner → Runner path. It contains the following code − #include “AppDelegate.h” #include “GeneratedPluginRegistrant.h” @implementation AppDelegate – (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions { // [GeneratedPluginRegistrant registerWithRegistry:self]; // Override point for customization after application launch. return [super application:application didFinishLaunchingWithOptions:launchOptions]; } @end We have added a method, openBrowser to open browser with specified url. It accepts single argument, url. – (void)openBrowser:(NSString *)urlString { NSURL *url = [NSURL URLWithString:urlString]; UIApplication *application = [UIApplication sharedApplication]; [application openURL:url]; } In didFinishLaunchingWithOptions method, find the controller and set it in controller variable. FlutterViewController* controller = (FlutterViewController*)self.window.rootViewController; In didFinishLaunchingWithOptions method, set the browser channel as flutterapp.tutorialspoint.com/browse − FlutterMethodChannel* browserChannel = [ FlutterMethodChannel methodChannelWithName: @”flutterapp.tutorialspoint.com/browser” binaryMessenger:controller]; Create a variable, weakSelf and set current class − __weak typeof(self) weakSelf = self; Now, implement setMethodCallHandler. Call openBrowser by matching call.method. Get url by invoking call.arguments and pass it while calling openBrowser. [browserChannel setMethodCallHandler:^(FlutterMethodCall* call, FlutterResult result) { if ([@”openBrowser” isEqualToString:call.method]) { NSString *url = call.arguments[@”url”]; [weakSelf openBrowser:url]; } else { result(FlutterMethodNotImplemented); } }]; The complete code is as follows − #include “AppDelegate.h” #include “GeneratedPluginRegistrant.h” @implementation AppDelegate – (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions { // custom code starts FlutterViewController* controller = (FlutterViewController*)self.window.rootViewController; FlutterMethodChannel* browserChannel = [ FlutterMethodChannel methodChannelWithName: @”flutterapp.tutorialspoint.com /browser” binaryMessenger:controller]; __weak typeof(self) weakSelf = self; [browserChannel setMethodCallHandler:^( FlutterMethodCall* call, FlutterResult result) { if ([@”openBrowser” isEqualToString:call.method]) { NSString *url = call.arguments[@”url”]; [weakSelf openBrowser:url]; } else { result(FlutterMethodNotImplemented); } }]; // custom code ends [GeneratedPluginRegistrant registerWithRegistry:self]; // Override point for customization after application launch. return [super application:application didFinishLaunchingWithOptions:launchOptions]; } – (void)openBrowser:(NSString *)urlString { NSURL *url = [NSURL URLWithString:urlString]; UIApplication *application = [UIApplication sharedApplication]; [application openURL:url]; } @end Open project setting. Go to Capabilities and enable Background Modes. Add *Background fetch and Remote Notification**. Now, run the application. It works similar to Android version but the Safari browser will be opened instead of chrome. Learn online work project make money
Flutter – Writing Android Specific Code Flutter provides a general framework to access platform specific feature. This enables the developer to extend the functionality of the Flutter framework using platform specific code. Platform specific functionality like camera, battery level, browser, etc., can be accessed easily through the framework. The general idea of accessing the platform specific code is through simple messaging protocol. Flutter code, Client and the platform code and Host binds to a common Message Channel. Client sends message to the Host through the Message Channel. Host listens on the Message Channel, receives the message and does the necessary functionality and finally, returns the result to the Client through Message Channel. The platform specific code architecture is shown in the block diagram given below − The messaging protocol uses a standard message codec (StandardMessageCodec class) that supports binary serialization of JSON-like values such as numbers, strings, boolean, etc., The serialization and de-serialization works transparently between the client and the host. Let us write a simple application to open a browser using Android SDK and understand how Create a new Flutter application in Android studio, flutter_browser_app Replace main.dart code with below code − import ”package:flutter/material.dart void main() => runApp(MyApp()); class MyApp extends StatelessWidget { @override Widget build(BuildContext context) { return MaterialApp( title: ”Flutter Demo”, theme: ThemeData( primarySwatch: Colors.blue, ), home: MyHomePage(title: ”Flutter Demo Home Page”), ); } } class MyHomePage extends StatelessWidget { MyHomePage({Key key, this.title}) : super(key: key); final String title; @override Widget build(BuildContext context) { return Scaffold( appBar: AppBar( title: Text(this.title), ), body: Center( child: RaisedButton( child: Text(”Open Browser”), onPressed: null, ), ), ); } } Here, we have created a new button to open the browser and set its onPressed method as null. Now, import the following packages − import ”dart:async import ”package:flutter/services.dart Here, services.dart include the functionality to invoke platform specific code. Create a new message channel in the MyHomePage widget. static const platform = const MethodChannel(”flutterapp.tutorialspoint.com/browser”); Write a method, _openBrowser to invoke platform specific method, openBrowser method through message channel. Future<void> _openBrowser() async { try { final int result = await platform.invokeMethod( ”openBrowser”, <String, String>{ ”url”: “https://flutter.dev” } ); } on PlatformException catch (e) { // Unable to open the browser print(e); } } Here, we have used platform.invokeMethod to invoke openBrowser (explained in coming steps). openBrowser has an argument, url to open a specific url. Change the value of onPressed property of the RaisedButton from null to _openBrowser. onPressed: _openBrowser, Open MainActivity.java (inside the android folder) and import the required library − import android.app.Activity; import android.content.Intent; import android.net.Uri; import android.os.Bundle; import io.flutter.app.FlutterActivity; import io.flutter.plugin.common.MethodCall; import io.flutter.plugin.common.MethodChannel; import io.flutter.plugin.common.MethodChannel.MethodCallHandler; import io.flutter.plugin.common.MethodChannel.Result; import io.flutter.plugins.GeneratedPluginRegistrant; Write a method, openBrowser to open a browser private void openBrowser(MethodCall call, Result result, String url) { Activity activity = this; if (activity == null) { result.error(“ACTIVITY_NOT_AVAILABLE”, “Browser cannot be opened without foreground activity”, null); return; } Intent intent = new Intent(Intent.ACTION_VIEW); intent.setData(Uri.parse(url)); activity.startActivity(intent); result.success((Object) true); } Now, set channel name in the MainActivity class − private static final String CHANNEL = “flutterapp.tutorialspoint.com/browser”; Write android specific code to set message handling in the onCreate method − new MethodChannel(getFlutterView(), CHANNEL).setMethodCallHandler( new MethodCallHandler() { @Override public void onMethodCall(MethodCall call, Result result) { String url = call.argument(“url”); if (call.method.equals(“openBrowser”)) { openBrowser(call, result, url); } else { result.notImplemented(); } } }); Here, we have created a message channel using MethodChannel class and used MethodCallHandler class to handle the message. onMethodCall is the actual method responsible for calling the correct platform specific code by the checking the message. onMethodCall method extracts the url from message and then invokes the openBrowser only when the method call is openBrowser. Otherwise, it returns notImplemented method. The complete source code of the application is as follows − main.dart MainActivity.java package com.tutorialspoint.flutterapp.flutter_browser_app; import android.app.Activity; import android.content.Intent; import android.net.Uri; import android.os.Bundle; import io.flutter.app.FlutterActivity; import io.flutter.plugin.common.MethodCall; import io.flutter.plugin.common.MethodChannel.Result; import io.flutter.plugins.GeneratedPluginRegistrant; public class MainActivity extends FlutterActivity { private static final String CHANNEL = “flutterapp.tutorialspoint.com/browser”; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); GeneratedPluginRegistrant.registerWith(this); new MethodChannel(getFlutterView(), CHANNEL).setMethodCallHandler( new MethodCallHandler() { @Override public void onMethodCall(MethodCall call, Result result) { String url = call.argument(“url”); if (call.method.equals(“openBrowser”)) { openBrowser(call, result, url); } else { result.notImplemented(); } } } ); } private void openBrowser(MethodCall call, Result result, String url) { Activity activity = this; if (activity == null) { result.error( “ACTIVITY_NOT_AVAILABLE”, “Browser cannot be opened without foreground activity”, null ); return; } Intent intent = new Intent(Intent.ACTION_VIEW); intent.setData(Uri.parse(url)); activity.startActivity(intent); result.success((Object) true); } } main.dart import ”package:flutter/material.dart import ”dart:async import ”package:flutter/services.dart void main() => runApp(MyApp()); class MyApp extends StatelessWidget { @override Widget build(BuildContext context) { return MaterialApp( title: ”Flutter Demo”, theme: ThemeData( primarySwatch: Colors.blue, ), home: MyHomePage( title: ”Flutter Demo Home Page” ), ); } } class MyHomePage extends StatelessWidget { MyHomePage({Key key, this.title}) : super(key: key); final String title; static const platform = const MethodChannel(”flutterapp.tutorialspoint.com/browser”); Future<void> _openBrowser() async { try { final int result = await platform.invokeMethod(”openBrowser”, <String, String>{ ”url”: “https://flutter.dev” }); } on PlatformException catch (e) { // Unable to open the browser print(e); } } @override Widget build(BuildContext context) { return Scaffold( appBar: AppBar( title: Text(this.title), ), body: Center( child: RaisedButton( child: Text(”Open Browser”), onPressed: _openBrowser, ), ), ); } } Run the application and click the Open Browser button and you can see that the browser is launched. The Browser app – Home page is as shown in the screenshot here − Learn online work project make money
Flutter – Writting Advanced Applications In this chapter, we are going to learn how to write a full fledged mobile application, expense_calculator. The purpose of the expense_calculator is to store our expense information. The complete feature of the application is as follows − Expense list. Form to enter new expenses. Option to edit / delete the existing expenses. Total expenses at any instance. We are going to program the expense_calculator application using below mentioned advanced features of Flutter framework. Advanced use of ListView to show the expense list. Form programming. SQLite database programming to store our expenses. scoped_model state management to simplify our programming. Let us start programming the expense_calculator application. Create a new Flutter application, expense_calculator in Android studio. Open pubspec.yaml and add package dependencies. dependencies: flutter: sdk: flutter sqflite: ^1.1.0 path_provider: ^0.5.0+1 scoped_model: ^1.0.1 intl: any Observe these points here − sqflite is used for SQLite database programming. path_provider is used to get system specific application path. scoped_model is used for state management. intl is used for date formatting. Android studio will display the following alert that the pubspec.yaml is updated. Click Get dependencies option. Android studio will get the package from Internet and properly configure it for the application. Remove the existing code in main.dart. Add new file, Expense.dart to create Expense class. Expense class will have the below properties and methods. property: id − Unique id to represent an expense entry in SQLite database. property: amount − Amount spent. property: date − Date when the amount is spent. property: category − Category represents the area in which the amount is spent. e.g Food, Travel, etc., formattedDate − Used to format the date property fromMap − Used to map the field from database table to the property in the expense object and to create a new expense object. factory Expense.fromMap(Map<String, dynamic> data) { return Expense( data[”id”], data[”amount”], DateTime.parse(data[”date”]), data[”category”] ); } toMap − Used to convert the expense object to Dart Map, which can be further used in database programming Map<String, dynamic> toMap() => { “id” : id, “amount” : amount, “date” : date.toString(), “category” : category, }; columns − Static variable used to represent the database field. Enter and save the following code into the Expense.dart file. import ”package:intl/intl.dart class Expense { final int id; final double amount; final DateTime date; final String category; String get formattedDate { var formatter = new DateFormat(”yyyy-MM-dd”); return formatter.format(this.date); } static final columns = [”id”, ”amount”, ”date”, ”category”]; Expense(this.id, this.amount, this.date, this.category); factory Expense.fromMap(Map<String, dynamic> data) { return Expense( data[”id”], data[”amount”], DateTime.parse(data[”date”]), data[”category”] ); } Map<String, dynamic> toMap() => { “id” : id, “amount” : amount, “date” : date.toString(), “category” : category, }; } The above code is simple and self explanatory. Add new file, Database.dart to create SQLiteDbProvider class. The purpose of the SQLiteDbProvider class is as follows − Get all expenses available in the database using getAllExpenses method. It will be used to list all the user’s expense information. Future<List<Expense>> getAllExpenses() async { final db = await database; List<Map> results = await db.query( “Expense”, columns: Expense.columns, orderBy: “date DESC” ); List<Expense> expenses = new List(); results.forEach((result) { Expense expense = Expense.fromMap(result); expenses.add(expense); }); return expenses; } Get a specific expense information based on expense identity available in the database using getExpenseById method. It will be used to show the particular expense information to the user. Future<Expense> getExpenseById(int id) async { final db = await database; var result = await db.query(“Expense”, where: “id = “, whereArgs: [id]); return result.isNotEmpty ? Expense.fromMap(result.first) : Null; } Get the total expenses of the user using getTotalExpense method. It will be used to show the current total expense to the user. Future<double> getTotalExpense() async { final db = await database; List<Map> list = await db.rawQuery( “Select SUM(amount) as amount from expense” ); return list.isNotEmpty ? list[0][“amount”] : Null; } Add new expense information into the database using insert method. It will be used to add new expense entry into the application by the user. Future<Expense> insert(Expense expense) async { final db = await database; var maxIdResult = await db.rawQuery( “SELECT MAX(id)+1 as last_inserted_id FROM Expense” ); var id = maxIdResult.first[“last_inserted_id”]; var result = await db.rawInsert( “INSERT Into Expense (id, amount, date, category)” ” VALUES (?, ?, ?, ?)”, [ id, expense.amount, expense.date.toString(), expense.category ] ); return Expense(id, expense.amount, expense.date, expense.category); } Update existing expense information using update method. It will be used to edit and update existing expense entry available in the system by the user. update(Expense product) async { final db = await database; var result = await db.update(“Expense”, product.toMap(), where: “id = ?”, whereArgs: [product.id]); return result; } Delete existing expense information using delete method. It will be used remove the existing expense entry available in the system by the user. delete(int id) async { final db = await database; db.delete(“Expense”, where: “id = ?”, whereArgs: [id]); } The complete code of the SQLiteDbProvider class is as follows − import ”dart:async import ”dart:io import ”package:path/path.dart import ”package:path_provider/path_provider.dart import ”package:sqflite/sqflite.dart import ”Expense.dart class SQLiteDbProvider { SQLiteDbProvider._(); static final SQLiteDbProvider db = SQLiteDbProvider._(); static Database _database; Future<Database> get database async { if (_database != null) return _database; _database = await initDB(); return _database; } initDB() async { Directory documentsDirectory = await getApplicationDocumentsDirectory(); String path = join(documentsDirectory.path, “ExpenseDB2.db”); return await openDatabase( path, version: 1, onOpen:(db){}, onCreate: (Database db, int version) async { await db.execute( “CREATE TABLE Expense ( “”id INTEGER PRIMARY KEY,” “amount REAL,” “date TEXT,” “category TEXT”” ) “); await db.execute( “INSERT INTO Expense (”id”, ”amount”, ”date”, ”category”) values (?, ?, ?, ?)”,[1, 1000, ”2019-04-01 10:00:00”, “Food”] ); /*await db.execute( “INSERT INTO Product (”id”, ”name”, ”description”, ”price”, ”image”) values (?, ?, ?, ?, ?)”, [ 2, “Pixel”, “Pixel is the most feature phone ever”, 800, “pixel.png” ] ); await db.execute( “INSERT INTO Product (”id”, ”name”, ”description”, ”price”, ”image”) values (?, ?, ?, ?, ?)”, [ 3, “Laptop”, “Laptop is most productive development tool”, 2000, “laptop.png” ] ); await db.execute( “INSERT INTO Product (”id”, ”name”, ”description”, ”price”, ”image”) values (?, ?, ?, ?,
Flutter – Database Concepts Flutter provides many advanced packages to work with databases. The most important packages are − sqflite − Used to access and manipulate SQLite database, and firebase_database − Used to access and manipulate cloud hosted NoSQL database from Google. In this chapter, let us discuss each of them in detail. SQLite SQLite database is the de-facto and standard SQL based embedded database engine. It is small and time-tested database engine. sqflite package provides a lot of functionality to work efficiently with SQLite database. It provides standard methods to manipulate SQLite database engine. The core functionality provided by sqflite package is as follows − Create / Open (openDatabase method) a SQLite database. Execute SQL statement (execute method) against SQLite database. Advanced query methods (query method) to reduce to code required to query and get information from SQLite database. Let us create a product application to store and fetch product information from a standard SQLite database engine using sqflite package and understand the concept behind the SQLite database and sqflite package. Create a new Flutter application in Android studio, product_sqlite_app. Replace the default startup code (main.dart) with our product_rest_app code. Copy the assets folder from product_nav_app to product_rest_app and add assets inside the *pubspec.yaml` file. flutter: assets: – assets/appimages/floppy.png – assets/appimages/iphone.png – assets/appimages/laptop.png – assets/appimages/pendrive.png – assets/appimages/pixel.png – assets/appimages/tablet.png Configure sqflite package in the pubspec.yaml file as shown below − dependencies: sqflite: any Use the latest version number of sqflite in place of any Configure path_provider package in the pubspec.yaml file as shown below − dependencies: path_provider: any Here, path_provider package is used to get temporary folder path of the system and path of the application. Use the latest version number of sqflite in place of any. Android studio will alert that the pubspec.yaml is updated. Click Get dependencies option. Android studio will get the package from Internet and properly configure it for the application. In database, we need primary key, id as additional field along with Product properties like name, price, etc., So, add id property in the Product class. Also, add a new method, toMap to convert product object into Map object. fromMap and toMap are used to serialize and de- serialize the Product object and it is used in database manipulation methods. class Product { final int id; final String name; final String description; final int price; final String image; static final columns = [“id”, “name”, “description”, “price”, “image”]; Product(this.id, this.name, this.description, this.price, this.image); factory Product.fromMap(Map<String, dynamic> data) { return Product( data[”id”], data[”name”], data[”description”], data[”price”], data[”image”], ); } Map<String, dynamic> toMap() => { “id”: id, “name”: name, “description”: description, “price”: price, “image”: image }; } Create a new file, Database.dart in the lib folder to write SQLite related functionality. Import necessary import statement in Database.dart. import ”dart:async import ”dart:io import ”package:path/path.dart import ”package:path_provider/path_provider.dart import ”package:sqflite/sqflite.dart import ”Product.dart Note the following points here − async is used to write asynchronous methods. io is used to access files and directories. path is used to access dart core utility function related to file paths. path_provider is used to get temporary and application path. sqflite is used to manipulate SQLite database. Create a new class SQLiteDbProvider Declare a singleton based, static SQLiteDbProvider object as specified below − class SQLiteDbProvider { SQLiteDbProvider._(); static final SQLiteDbProvider db = SQLiteDbProvider._(); static Database _database; } SQLiteDBProvoider object and its method can be accessed through the static db variable. SQLiteDBProvoider.db.<emthod> Create a method to get database (Future option) of type Future<Database>. Create product table and load initial data during the creation of the database itself. Future<Database> get database async { if (_database != null) return _database; _database = await initDB(); return _database; } initDB() async { Directory documentsDirectory = await getApplicationDocumentsDirectory(); String path = join(documentsDirectory.path, “ProductDB.db”); return await openDatabase( path, version: 1, onOpen: (db) {}, onCreate: (Database db, int version) async { await db.execute( “CREATE TABLE Product (” “id INTEGER PRIMARY KEY,” “name TEXT,” “description TEXT,” “price INTEGER,” “image TEXT” “)” ); await db.execute( “INSERT INTO Product (”id”, ”name”, ”description”, ”price”, ”image”) values (?, ?, ?, ?, ?)”, [1, “iPhone”, “iPhone is the stylist phone ever”, 1000, “iphone.png”] ); await db.execute( “INSERT INTO Product (”id”, ”name”, ”description”, ”price”, ”image”) values (?, ?, ?, ?, ?)”, [2, “Pixel”, “Pixel is the most feature phone ever”, 800, “pixel.png”] ); await db.execute( “INSERT INTO Product (”id”, ”name”, ”description”, ”price”, ”image”) values (?, ?, ?, ?, ?)”, [3, “Laptop”, “Laptop is most productive development tool”, 2000, “laptop.png”] ); await db.execute( “INSERT INTO Product (”id”, ”name”, ”description”, ”price”, ”image”) values (?, ?, ?, ?, ?)”, [4, “Tablet”, “Laptop is most productive development tool”, 1500, “tablet.png”] ); await db.execute( “INSERT INTO Product (”id”, ”name”, ”description”, ”price”, ”image”) values (?, ?, ?, ?, ?)”, [5, “Pendrive”, “Pendrive is useful storage medium”, 100, “pendrive.png”] ); await db.execute( “INSERT INTO Product (”id”, ”name”, ”description”, ”price”, ”image”) values (?, ?, ?, ?, ?)”, [6, “Floppy Drive”, “Floppy drive is useful rescue storage medium”, 20, “floppy.png”] ); } ); } Here, we have used the following methods − getApplicationDocumentsDirectory − Returns application directory path join − Used to create system specific path. We have used it to create database path. openDatabase − Used to open a SQLite database onOpen − Used to write code while opening a database onCreate − Used to write code while a database is created for the first time db.execute − Used to execute SQL queries. It accepts a query. If the query has placeholder (?), then it accepts values as list in the second argument. Write a method to get all products in the database − Future<List<Product>> getAllProducts() async { final db = await database; List<Map> results = await db.query(“Product”, columns: Product.columns, orderBy: “id ASC”); List<Product> products = new List(); results.forEach((result) { Product product = Product.fromMap(result); products.add(product); }); return products; } Here, we have done the following − Used query method to fetch all the product information. query provides shortcut to query a table information without writing the entire query. query method will generate the proper query itself by using
Flutter – Animation Animation is a complex procedure in any mobile application. In spite of its complexity, Animation enhances the user experience to a new level and provides a rich user interaction. Due to its richness, animation becomes an integral part of modern mobile application. Flutter framework recognizes the importance of Animation and provides a simple and intuitive framework to develop all types of animations. Introduction Animation is a process of showing a series of images / picture in a particular order within a specific duration to give an illusion of movement. The most important aspects of the animation are as follows − Animation have two distinct values: Start value and End value. The animation starts from Start value and goes through a series of intermediate values and finally ends at End values. For example, to animate a widget to fade away, the initial value will be the full opacity and the final value will be the zero opacity. The intermediate values may be linear or non-linear (curve) in nature and it can be configured. Understand that the animation works as it is configured. Each configuration provides a different feel to the animation. For example, fading a widget will be linear in nature whereas bouncing of a ball will be non-linear in nature. The duration of the animation process affects the speed (slowness or fastness) of the animation. The ability to control the animation process like starting the animation, stopping the animation, repeating the animation to set number of times, reversing the process of animation, etc., In Flutter, animation system does not do any real animation. Instead, it provides only the values required at every frame to render the images. Animation Based Classes Flutter animation system is based on Animation objects. The core animation classes and its usage are as follows − Animation Generates interpolated values between two numbers over a certain duration. The most common Animation classes are − Animation<double> − interpolate values between two decimal number Animation<Color> − interpolate colors between two color Animation<Size> − interpolate sizes between two size AnimationController − Special Animation object to control the animation itself. It generates new values whenever the application is ready for a new frame. It supports linear based animation and the value starts from 0.0 to 1.0 controller = AnimationController(duration: const Duration(seconds: 2), vsync: this); Here, controller controls the animation and duration option controls the duration of the animation process. vsync is a special option used to optimize the resource used in the animation. CurvedAnimation Similar to AnimationController but supports non-linear animation. CurvedAnimation can be used along with Animation object as below − controller = AnimationController(duration: const Duration(seconds: 2), vsync: this); animation = CurvedAnimation(parent: controller, curve: Curves.easeIn) Tween<T> Derived from Animatable<T> and used to generate numbers between any two numbers other than 0 and 1. It can be used along with Animation object by using animate method and passing actual Animation object. AnimationController controller = AnimationController( duration: const Duration(milliseconds: 1000), vsync: this); Animation<int> customTween = IntTween( begin: 0, end: 255).animate(controller); Tween can also used along with CurvedAnimation as below − AnimationController controller = AnimationController( duration: const Duration(milliseconds: 500), vsync: this); final Animation curve = CurvedAnimation(parent: controller, curve: Curves.easeOut); Animation<int> customTween = IntTween(begin: 0, end: 255).animate(curve); Here, controller is the actual animation controller. curve provides the type of non-linearity and the customTween provides custom range from 0 to 255. Work flow of the Flutter Animation The work flow of the animation is as follows − Define and start the animation controller in the initState of the StatefulWidget. AnimationController(duration: const Duration(seconds: 2), vsync: this); animation = Tween<double>(begin: 0, end: 300).animate(controller); controller.forward(); Add animation based listener, addListener to change the state of the widget. animation = Tween<double>(begin: 0, end: 300).animate(controller) ..addListener(() { setState(() { // The state that has changed here is the animation object’s value. }); }); Build-in widgets, AnimatedWidget and AnimatedBuilder can be used to skip this process. Both widget accepts Animation object and get current values required for the animation. Get the animation values during the build process of the widget and then apply it for width, height or any relevant property instead of the original value. child: Container( height: animation.value, width: animation.value, child: <Widget>, ) Working Application Let us write a simple animation based application to understand the concept of animation in Flutter framework. Create a new Flutter application in Android studio, product_animation_app. Copy the assets folder from product_nav_app to product_animation_app and add assets inside the pubspec.yaml file. flutter: assets: – assets/appimages/floppy.png – assets/appimages/iphone.png – assets/appimages/laptop.png – assets/appimages/pendrive.png – assets/appimages/pixel.png – assets/appimages/tablet.png Remove the default startup code (main.dart). Add import and basic main function. import ”package:flutter/material.dart void main() => runApp(MyApp()); Create the MyApp widget derived from StatefulWidgtet. class MyApp extends StatefulWidget { _MyAppState createState() => _MyAppState(); } Create _MyAppState widget and implement initState and dispose in addition to default build method. class _MyAppState extends State<MyApp> with SingleTickerProviderStateMixin { Animation<double> animation; AnimationController controller; @override void initState() { super.initState(); controller = AnimationController( duration: const Duration(seconds: 10), vsync: this ); animation = Tween<double>(begin: 0.0, end: 1.0).animate(controller); controller.forward(); } // This widget is the root of your application. @override Widget build(BuildContext context) { controller.forward(); return MaterialApp( title: ”Flutter Demo”, theme: ThemeData(primarySwatch: Colors.blue,), home: MyHomePage(title: ”Product layout demo home page”, animation: animation,) ); } @override void dispose() { controller.dispose(); super.dispose(); } } Here, In initState method, we have created an animation controller object (controller), an animation object (animation) and started the animation using controller.forward. In dispose method, we have disposed the animation controller object (controller). In build method, send animation to MyHomePage widget through constructor. Now, MyHomePage widget can use the animation object to animate its content. Now, add ProductBox widget class ProductBox extends StatelessWidget { ProductBox({Key key, this.name, this.description, this.price, this.image}) : super(key: key); final String name; final String description; final int price; final String image; Widget build(BuildContext context) { return Container( padding: EdgeInsets.all(2), height: 140, child: Card( child: Row( mainAxisAlignment: MainAxisAlignment.spaceEvenly, children: <Widget>[ Image.asset(“assets/appimages/” + image), Expanded( child: Container( padding: EdgeInsets.all(5), child: Column( mainAxisAlignment: MainAxisAlignment.spaceEvenly, children: <Widget>[ Text(this.name, style: TextStyle(fontWeight:
Flutter – Architecture Application ”; Previous Next In this chapter, let us discuss the architecture of the Flutter framework. Widgets The core concept of the Flutter framework is In Flutter, Everything is a widget. Widgets are basically user interface components used to create the user interface of the application. In Flutter, the application is itself a widget. The application is the top- level widget and its UI is build using one or more children (widgets), which again build using its children widgets. This composability feature helps us to create a user interface of any complexity. For example, the widget hierarchy of the hello world application (created in previous chapter) is as specified in the following diagram − Here the following points are worth notable − 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 Gestures Flutter widgets support interaction through a special widget, GestureDetector. GestureDetector is an invisible widget having the ability to capture user interactions such as tapping, dragging, etc., of its child widget. Many native widgets of Flutter support interaction through the use of GestureDetector. We can also incorporate interactive feature into the existing widget by composing it with the GestureDetector widget. We will learn the gestures separately in the upcoming chapters. Concept of State Flutter widgets support State maintenance by providing a special widget, StatefulWidget. Widget needs to be derived from StatefulWidget widget to support state maintenance and all other widget should be derived from StatefulWidget. Flutter widgets are reactive in native. This is similar to reactjs and StatefulWidget will be auto re- rendered whenever its internal state is changed. The re-rendering is optimized by finding the difference between old and new widget UI and rendering only the necessary changes Layers The most important concept of Flutter framework is that the framework is grouped into multiple category in terms of complexity and clearly arranged in layers of decreasing complexity. A layer is build using its immediate next level layer. The top most layer is widget specific to Android and iOS. The next layer has all flutter native widgets. The next layer is Rendering layer, which is low level renderer component and renders everything in the flutter app. Layers goes down to core platform specific code The general overview of a layer in Flutter is specified in the below diagram − The following points summarize the architecture of Flutter − In Flutter, everything is a widget and a complex widget is composed of already existing widgets. Interactive features can be incorporated whenever necessary using GestureDetector widget. The state of a widget can be maintained whenever necessary using StatefulWidget widget. Flutter offers layered design so that any layer can be programmed depending on the complexity of the task. We will discuss all these concepts in detail in the upcoming chapters. Print Page Previous Next Advertisements ”;
Flutter – Home
Flutter Tutorial Job Search PDF Version Quick Guide Resources Discussion This Flutter tutorial has everything you need to know about the Flutter framework, from its installation to writing advanced applications. Flutter is a UI toolkit used to develop applications for both mobile and desktop using a single programming language and code base. This tutorial would be the right choice for someone who is looking forward to learning a framework for developing an application. What is Flutter? Flutter is an open source framework developed by Google to create high quality, high performance mobile applications across mobile operating systems – Android and iOS. It provides a simple, powerful, efficient and easy to understand SDK to write mobile applications in Google’s own language, Dart. With Flutter, we can write the app”s code once and deploy it on multiple platforms(Android, IOS, Desktop). Due to its flexibility and performance capabilities, Flutter is the top pick for modern app development across various platforms. What Makes Flutter Unique? Flutter has several features and design principles that set it apart from other frameworks. It neither uses WebView nor the OEM widgets; instead, it uses customizable widgets, which enhances the application”s interface. Also, the hot reload feature lets developers make changes in the app without restarting. History of Flutter Flutter, developed by Google, has undergone significant evolution since its launch in 2015 as “Sky”. Well, the first stable release of Flutter 1.0 was in 2018 as a goal to create a cross-platform UI toolkit. Significant updates followed Flutter 2.0”s release in 2021. With each release, Flutter enhanced its features, performance and ecosystem. Applications Made with Flutter Framework There are quite a few popular applications that are made with the Flutter framework. Few of the are − Google Products – Google Ads, Google pay Reflectly – Personal Journal App Alibaba”s Xianyu – Ecommerce Platform eBay Motor Nubank Hamilton Mobile App Development with Flutter Flutter is an open-source UI toolkit developed by Google that is used to build, network, and integrate apps from a single code base. Following are the steps that would take you through the process of developing, testing and deploying a mobile application − Set Up the Development Environment Create a New Flutter Project Build your app”s interface by defining Widgets Implement application logic Add functionality and features Test your application Debug and Optimize Build and Deploy The steps above are detailed in the following chapters of the tutorial. Jobs & Opportunities Learning the Flutter framework can help land many jobs since there are quite a few companies that use Flutter to develop their app, like eBay, BMW, Google, and Toyota. As companies adopt Flutter for app development, the demand for skilled developers is set to rise. Some job roles that you can explore after Flutter are − Flutter Developer Mobile App Developer Flutter Engineer Mobile Architect Prerequisites to Learn Flutter This tutorial is written assuming that the readers are already aware of what a Framework is and that the readers have a sound knowledge of Object Oriented Programming and basic knowledge of Android framework and Dart programming. If you are a beginner to any of these concepts, we suggest you go through tutorials related to them first before you start with Flutter. Who Should Learn Flutter? This tutorial is prepared for professionals who are aspiring to make a career in the field of mobile applications. This tutorial is intended to make you comfortable in getting started with the Flutter framework and its various functionalities. Frequently Asked Questions about Flutter There are some important frequently asked questions (FAQs) about Flutter framework; this section lists them down along with their answers briefly − What is Flutter? Flutter is an open-source UI toolkit developed by Google for creating natively compiled applications from a single codebase for mobile, web and desktop platforms using Dart programming language. Why is Dart programming language used? Dart is used for Flutter because it is optimized for developing user interfaces with features like async programming and strong typing. It also allows for real-time code changes without restarting the app. What does Flutter do? Flutter is usually used to make applications come to life. Apart from that, developers use it to ease the development of mobile applications. It reduces the complexity and cost of app production across iOS and Android. What kind of apps can be built using Flutter? Flutter can be used to develop applications for mobile (iOS and Android), web applications and desktop applications. It is preferred for creating anything from simple e-commerce platforms to complex applications. What are the benefits of using Flutter? Flutter allows us to develop applications across mobile, web and desktop platforms, using a single code. Its features like hot reload and native code compilation enhances the performance of the application. Also it consists of a rich set of customizable UI widgets that improves user experience. How can I get started with Flutter? To get started with Flutter, install the Flutter SDK and set up an IDE like Visual Studio Code with Flutter and Dart plugins. To develop your first application, explore official documentation and the tutorial. Print Page Previous Next Advertisements ”;
Flutter – Accessing REST API
Flutter – Accessing REST API ”; Previous Next Flutter provides http package to consume HTTP resources. http is a Future-based library and uses await and async features. It provides many high level methods and simplifies the development of REST based mobile applications. Basic Concepts http package provides a high level class and http to do web requests. http class provides functionality to perform all types of HTTP requests. http methods accept a url, and additional information through Dart Map (post data, additional headers, etc.,). It requests the server and collects the response back in async/await pattern. For example, the below code reads the data from the specified url and print it in the console. print(await http.read(”https://flutter.dev/”)); Some of the core methods are as follows − read − Request the specified url through GET method and return back the response as Future<String> get − Request the specified url through GET method and return back the response as Future<Response>. Response is a class holding the response information. post − Request the specified url through POST method by posting the supplied data and return back the response as Future<Response> put − Request the specified url through PUT method and return back the response as Future <Response> head − Request the specified url through HEAD method and return back the response as Future<Response> delete − Request the specified url through DELETE method and return back the response as Future<Response> http also provides a more standard HTTP client class, client. client supports persistent connection. It will be useful when a lot of request to be made to a particular server. It needs to be closed properly using close method. Otherwise, it is similar to http class. The sample code is as follows − var client = new http.Client(); try { print(await client.get(”https://flutter.dev/”)); } finally { client.close(); } Accessing Product service API Let us create a simple application to get product data from a web server and then show the products using ListView. Create a new Flutter application in Android studio, product_rest_app. Replace the default startup code (main.dart) with our product_nav_app code. Copy the assets folder from product_nav_app to product_rest_app and add assets inside the pubspec.yaml file. flutter: assets: – assets/appimages/floppy.png – assets/appimages/iphone.png – assets/appimages/laptop.png – assets/appimages/pendrive.png – assets/appimages/pixel.png – assets/appimages/tablet.png Configure http package in the pubspec.yaml file as shown below − dependencies: http: ^0.12.0+2 Here, we will use the latest version of the http package. Android studio will send a package alert that the pubspec.yaml is updated. Click Get dependencies option. Android studio will get the package from Internet and properly configure it for the application. Import http package in the main.dart file − import ”dart:async”; import ”dart:convert”; import ”package:http/http.dart” as http; Create a new JSON file, products.json with product information as shown below − [ { “name”: “iPhone”, “description”: “iPhone is the stylist phone ever”, “price”: 1000, “image”: “iphone.png” }, { “name”: “Pixel”, “description”: “Pixel is the most feature phone ever”, “price”: 800, “image”: “pixel.png” }, { “name”: “Laptop”, “description”: “Laptop is most productive development tool”, “price”: 2000, “image”: “laptop.png” }, { “name”: “Tablet”, “description”: “Tablet is the most useful device ever for meeting”, “price”: 1500, “image”: “tablet.png” }, { “name”: “Pendrive”, “description”: “Pendrive is useful storage medium”, “price”: 100, “image”: “pendrive.png” }, { “name”: “Floppy Drive”, “description”: “Floppy drive is useful rescue storage medium”, “price”: 20, “image”: “floppy.png” } ] Create a new folder, JSONWebServer and place the JSON file, products.json. Run any web server with JSONWebServer as its root directory and get its web path. For example, http://192.168.184.1:8000/products.json. We can use any web server like apache, nginx etc., The easiest way is to install node based http-server application. Follow the steps given below to install and run http- server application Install Nodejs application (nodejs.org) Go to JSONWebServer folder. cd /path/to/JSONWebServer Install http-server package using npm. npm install -g http-server Now, run the server. http-server . -p 8000 Starting up http-server, serving . Available on: http://192.168.99.1:8000 http://127.0.0.1:8000 Hit CTRL-C to stop the server Create a new file, Product.dart in the lib folder and move the Product class into it. Write a factory constructor in the Product class, Product.fromMap to convert mapped data Map into the Product object. Normally, JSON file will be converted into Dart Map object and then, converted into relevant object (Product). factory Product.fromJson(Map<String, dynamic> data) { return Product( data[”name”], data[”description”], data[”price”], data[”image”], ); } The complete code of the Product.dart is as follows − class Product { final String name; final String description; final int price; final String image; Product(this.name, this.description, this.price, this.image); factory Product.fromMap(Map<String, dynamic> json) { return Product( json[”name”], json[”description”], json[”price”], json[”image”], ); } } Write two methods − parseProducts and fetchProducts – in the main class to fetch and load the product information from web server into the List<Product> object. List<Product> parseProducts(String responseBody) { final parsed = json.decode(responseBody).cast<Map<String, dynamic>>(); return parsed.map<Product>((json) =>Product.fromJson(json)).toList(); } Future<List<Product>> fetchProducts() async { final response = await http.get(”http://192.168.1.2:8000/products.json”); if (response.statusCode == 200) { return parseProducts(response.body); } else { throw Exception(”Unable to fetch