Flutter Capsule

  Article
Flutter
WIDGETS
Usama Sarwar
Usama Sarwar
Usama Sarwar
BEGINNER LEVEL FLUTTER APPS

Flutter Health Status

Run this command to check Flutter Status on your device

flutter doctor

Run this command to check available devices for Flutter

flutter devices

Run this command to upgrade Flutter

flutter upgrade

Run this command to configure Flutter

flutter config

Run this command to check Flutter Channel

flutter channel

Run this command to switch to Flutter Channel Beta, likewise you can switch back to stable

flutter channel beta

Run this command to Repair Pub Cache

flutter pub cache repair

Create App

Run this command to create an app, just replace app_name with your desired app name but without spaces and special characters except Underscore(_)

flutter create app_name

Specify Package Name

Create your Flutter app with this command to customize your app’s package name; Package name from the below command will be com.company.app_name You can change it accordingly

flutter create --org com.company app_name

Create Command for Release

flutter create --androidx -t app --org com.company -a kotlin -i swift app_name

Run App

Run this command to run a Flutter Project

flutter run

Run this command to check runner logs while running

flutter run -v

Run this command to run the project on specific device when there are muliple devices available replace device_ID with your device ID Sample: flutter run -d chrome to run flutter web project on Chrome Browser

flutter run -d device_ID

Run this command to run the flutter web project on specific port of localhost Sample: flutter run -d chrome --web-hostname localhost --web-port 8080 to run flutter web project on port localhost:8080 on Web Browser

flutter run -d chrome --web-hostname localhost --web-port [port_number]

Signing App

Step 1

Create a keystore If you have an existing keystore, skip to the next step. If not, create one by running the following at the command line:

./keytool -genkey -v -keystore ~/key.jks -keyalg RSA -keysize 2048 -validity 10000 -alias key

OR Run this if get error

.\keytool -genkey -v -keystore ~/key.jks -keyalg RSA -keysize 2048 -validity 10000 -alias key

Note: Keep this file private; do not check it into public source control. Note: keytool may not be in your path. It is part of the Java JDK, which is installed as part of Android Studio. For the concrete path, run flutter doctor -v and see the path printed after Java binary at: and then use that fully qualified path replacing java with keytool.

Step 2

Reference the keystore from the app Create a file named key.properties<Project>/android/key.properties that contains a reference to your keystore: Add these lines in /android/key.properties

storePassword= password from previous step
keyPassword= password from previous step
keyAlias= key
storeFile= location of the key store file, e.g. /Users/username/key.jks

Step 3

Add these lines above android{ } (near line 16) in /android/app/build.gradle

def keystorePropertiesFile = rootProject.file("key.properties") 
def keystoreProperties = new Properties() 
keystoreProperties.load(new FileInputStream(keystorePropertiesFile)) 

Add these lines in android{ } in /android/app/build.gradle

signingConfigs { 
	release { 
	keyAlias keystoreProperties['keyAlias']
	keyPassword keystoreProperties['keyPassword']
	storeFile file(keystoreProperties['storeFile'])
	storePassword keystoreProperties['storePassword'] 
	} 
} 
buildTypes { 
	release { 
	signingConfig signingConfigs.release 
	} 
}

Creating a plugin/dependency in Flutter

Step 1

Create a package first, using the following command:

flutter create --template-plugin --org --com.example --template= plugin --platform= android, ios, -a java -i objc plugin_name

Note: you can use the any language you prefer for android and ios. To add web support in your plugin use the following command:

flutter create --template=plugin --platform=web .

Step 2

Add the plugin code in plugin_name.dart and also arrange your pubspec.yaml and add following fields:

name: name of your plugin project
description: description of the plugin project
version: version of the package to be hosted on pub.dev
author: name of the author
homepage: link of the package's homepage
documentation: link of the plugin documentation
publish_to: specify where to publish the plugin it should be a link, if you do not want to publish it then place none instead of a link

environment:
    sdk:
       flutter:
      
dependencies:
// list any dependencies used by the plugin

dev_dependencies:
// list any dev dependencies used by the plugin

Step 3

Publishing the plugin package:

flutter publish --dry-run # this command will help you verify that everything is as intended
flutter pub publish # it will publish the plugin on pub.dev

Now, you have successfully published your plugin. You can check it by using the following link:

https://pub.dev/packages/YOUR_PACKAGE_NAME

Build App

Run this command to build Android .apk file

flutter build apk

Run this command to build Android .apk file in release mode

flutter build apk --release

Run this command to build Web root folder in release mode

flutter build web --release

Generate App Bundles

flutter build appbundle --target-platform android-arm,android-arm64,android-x64

Split the APKs per ABI

Run this command to reduce the APK Size to the minimum

flutter build apk --target-platform android-arm,android-arm64,android-x64 --split-per-abi

Flutter Build Web Release

Run this command to build web release for Flutter Web App

flutter build web --release --web-renderer html

Basic App

This is a very basic beginner level app that is showing two List Tiles in its body. To run this code copy and paste it in lib/main.dart

// Importing Material Library
import 'package:flutter/material.dart';

// Main Function of this App
// We will call runApp that is a built-in function that will run the App
void main() => runApp(
      // Material App is the outer most Parent Widget that will wrap the child widgets
      MaterialApp(
        // To remove the Debug Tag from the App
        debugShowCheckedModeBanner: false,
        // Setting App Theme data
        theme: ThemeData(
          primarySwatch: Colors.red,),
        // Title is the title of the app
        title: 'Messenger',
        // Home widget of Material App
        home: Scaffold(
          // App Bar of the App
          appBar: AppBar(
            // Title of the App Bar
            title: Text('Inbox'),
            // This is the leading icon on the App Bar
            leading: Icon(Icons.menu_open),
            // These are action icon(s) on the App Bar
            actions: [
              // padding for wraping with some space
              Padding(
                // padding: EdgeInsets.all(8.0), // Padding value set to 8.0 on all sides
                padding: EdgeInsets.only(right: 15.0), // Padding value set to 15.0 on right side
                child: Icon(Icons.create_sharp), // Added a favourite icon
              ),
            ],
          ),
          // This is the body of Scafold
          body: Column(
            // Alignment across main (Vertical) Axis
            mainAxisAlignment: MainAxisAlignment.start,
            // Alignment across cross (Horizontal) Axis
            crossAxisAlignment: CrossAxisAlignment.stretch,
            children: [
              // For setting some space around Card
              Padding(
                padding: const EdgeInsets.fromLTRB(8.0, 8.0, 8.0, 0.0),
                // Creating Card
                child: Card(
                  elevation: 5.0,
                  // Setting List Tile
                  child: ListTile(
                    // Setting Leading Icon
                    leading: Icon(
                      Icons.account_circle,
                      // Setting Size of the Icon
                      size: 40.0,
                      // Setting Icon Color
                      color: Colors.amber,
                    ),
                    // Setting Title of the List Tile
                    title: Text('Usama Sarwar'),
                    // Setting Sub-Title of the List Tile
                    subtitle: Text('Happy Birthday to you 🎂'),
                    // Setting Trailing Icon
                    trailing: Icon(
                      Icons.send,
                      color: Colors.amberAccent),),),),
              // For setting some space around Card
              Padding(
                padding: const EdgeInsets.fromLTRB(8.0, 8.0, 8.0, 0.0),
                // Creating Card
                child: Card(
                  elevation: 5.0,
                  // Setting List Tile
                  child: ListTile(
                    // Setting Leading Icon
                    leading: Icon(
                      Icons.account_circle,
                      // Setting Size of the Icon
                      size: 40.0,
                      // Setting Icon Color
                      color: Colors.grey[700],
                    ),
                    // Setting Title of the List Tile
                    title: Text('Ayesha Ali'),
                    // Setting Sub-Title of the List Tile
                    subtitle: Text('Let\'s meet at 10\'O Clock ⌚'),
                    // Setting Trailing Icon
                    trailing: Icon(
                      Icons.send,
                      color: Colors.grey[700],),),),),],),),),);

Stateless Widget

In Stateless widget the state of app can’t change. Here is an example of a counter app in which you can observe the chnaging value in the console but on UI it will not render. To render the value accourdingly you will have to use Stateful Widget that is the next example.

// Importing Material Library
import  'package:flutter/material.dart';

// Main Function of this App
// We will call runApp that is a built-in function that will run the App
void  main() => runApp(MyApp());

class  MyApp  extends  StatelessWidget {

// Initilized a variable
static  int number = 1;

// Function for performing task
void  increment() {
number++;
}

@override
Widget  build(BuildContext context) {
return  // Material App is the outer most Parent Widget that will wrap the child widgets
MaterialApp(
// To remove the Debug Tag from the App
debugShowCheckedModeBanner: false,

// Setting App Theme data
theme: ThemeData(
primarySwatch: Colors.red,
),

// Title is the title of the app
title: 'Stateless Widget',

// Home widget of Material App
home: Scaffold(

// App Bar of the App
appBar: AppBar(

// Title of the App Bar
title: Text('Stateless Widget Example'),

// These are action icon(s) on the App Bar
),
// Body of Scafold
body: Center(
// Display a text in the center
// This is how to display a text
child: Text(
// Concatination of a String with some variable
'Number: $number', // However this will not update
// Styling text
style: TextStyle(
// Setting fontSize
fontSize: 25.0,),),),

// FloatingActionButton Added
floatingActionButton: FloatingActionButton(
// Setting Icon
child: Icon(Icons.add),
// Setting action on button when it is pressed
onPressed: () {
// Funtion for the incrementation
increment();

// To check the value of number on console
print('Number: $number');
},),),);}}

Stateful Widget

In Stateful Widget, the state of the app can be changed. It renders everytime whenver it detectects the change in the value of some variable. Here is the sample code.

// Importing Material Library
import  'package:flutter/material.dart';

// Main Function of this App
// We will call runApp that is a built-in function that will run the App
void  main() => runApp(MyApp());
class  MyApp  extends  StatefulWidget {
@override
_MyAppState  createState() => _MyAppState();
}
class  _MyAppState  extends  State<MyApp> {

// Initilized a variable
static  int number = 1;

// Increment Function
void  increment() {
// Calling SetState will render the User Interface and update it accordingly
setState(() {
number++;
});}

@override
Widget  build(BuildContext context) {
return  // Material App is the outer most Parent Widget that will wrap the child widgets
MaterialApp(
// To remove the Debug Tag from the App
debugShowCheckedModeBanner: false,

// Setting App Theme data
theme: ThemeData(
primarySwatch: Colors.red,
),

// Title is the title of the app
title: 'Stateful Widget',

// Home widget of Material App
home: Scaffold(

// App Bar of the App
appBar: AppBar(

// Title of the App Bar
title: Text('Stateful Widget Example'),
// These are action icon(s) on the App Bar
),

// Body of Scafold
body: Center(
// Display a text in the center
// This is how to display a text
child: Text(
// Concatination of a String with some variable
'Number: $number', // However this will not update
// Styling text
style: TextStyle(
// Setting fontSize
fontSize: 25.0,
),),),
// FloatingActionButton Added
floatingActionButton: FloatingActionButton(
// Setting Icon
child: Icon(Icons.add),
// Setting action on button when it is pressed
onPressed: () {
// Funtion for the incrementation
increment();

// To check the value of number on console
print('Number: $number');},),),);}}

App Navigation

Navigator in Flutter application manages the routes and screen navigation. According to official docs: The navigator manages a stack of Route objects and provides methods for managing the stack, like Navigator.push and Navigator.pop.

import  'package:flutter/material.dart';
void  main() => runApp(Home());

class  Home  extends  StatelessWidget {
// Home Widget
@override
Widget  build(BuildContext context) {
return  MaterialApp(
debugShowCheckedModeBanner: false,
title: 'Routing Sample App',
// Initial Route when App Starts
initialRoute: '/',
// Named Routes for all widgets in App
routes: {
// We can use any string instead of '\'
'/': (context) => HomeScreen(), // Main Screen Route
'/S1': (context) => Screen1(), // This is child screen of Home Screen
'/S1/S2': (context) => Screen2(), // This is child screen of Screen 1
},);}}
  
// Home Screen Widget
class  HomeScreen  extends  StatelessWidget {
@override
Widget  build(BuildContext context) {
return  Scaffold(
appBar: AppBar(
title: Text('Home Screen'),
),
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Text('This is Home Screen'),
RaisedButton(
child: Text('Screen 1'),
// This will navigate to named route '/S1' that is Screen 1
onPressed: () => Navigator.pushNamed(context, '/S1'),
),],),),);}}
// Screen 1 Widget
class  Screen1  extends  StatelessWidget {
@override
Widget  build(BuildContext context) {
return  Scaffold(
appBar: AppBar(
title: Text('Screen 1'),
),
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Text('This is Screen 1'),
RaisedButton(
child: Text('Home Screen'),
// This will navigate to the parent screen from where it reached here
onPressed: () => Navigator.pop(context),
),
RaisedButton(
child: Text('Screen 2'),
// This will navigate to named route '/S1/S2' that is Screen 2
onPressed: () => Navigator.pushNamed(context, '/S1/S2'),
),],),),);}}  

// Screen 2 Widget
class  Screen2  extends  StatelessWidget {
@override
Widget  build(BuildContext context) {
return  Scaffold(
appBar: AppBar(
title: Text('Screen 2'),
),
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Text('This is Screen 2'),
RaisedButton(
child: Text('Home Screen'),
// This will navigate to named route '/' that is Home Screen
onPressed: () => Navigator.pushNamed(context, '/'),
),
RaisedButton(
child: Text('Screen 1'),
// This will navigate to the parent screen from where it reached here
onPressed: () => Navigator.pop(context),
),],),),);}}

ListView Builder

import  'package:flutter/material.dart';
void  main() => runApp(Home());

// List of items
List<String> list = ['Item 0'];
// Variable for incrementing value
int  num = 1;
class  Home  extends  StatelessWidget {
// Home Widget
@override
Widget  build(BuildContext context) {
return  MaterialApp(
debugShowCheckedModeBanner: false,
title: 'ListView Builder',
// Initial Route when App Starts
initialRoute: '/',
// Named Routes for all widgets in App
routes: {
// We can use any string instead of '\'
'/': (context) => HomeScreen(), // Main Screen Route
},);}}

class  HomeScreen  extends  StatefulWidget {
@override
_HomeScreenState  createState() => _HomeScreenState();
}

class  _HomeScreenState  extends  State<HomeScreen> {
// Function for adding value into the list
void  addItem() {
setState(() {
list.add('Item ' + '${num.toString()}');
});
print(list); // For console logs
num++;
}

// Function for deleting value from the list
void  delItem(int index) {
setState(() {
list.removeAt(index);
});
print(list); // For console logs
}

@override
Widget  build(BuildContext context) {
return  Scaffold(
appBar: AppBar(
backgroundColor: Colors.red,
title: Text('ListView Builder'),
actions: [
// Icon Button to add item into the list
IconButton(
icon: Icon(Icons.add),
onPressed: () {
addItem();
},),],),
body: ListView.builder(
// .length will automatically determine the size of list
itemCount: list.length,
itemBuilder: (context, index) {
return  Padding(
padding: EdgeInsets.fromLTRB(8.0, 5.0, 8.0, 0.0),
child: Card(
elevation: 5.0,
child: ListTile(
// To show Snackbar
onTap: () {
Scaffold.of(context).showSnackBar(
SnackBar(content: Text('You tapped on ${list[index]}')));
},
// Smile, because it's good for health
leading: Icon(
Icons.insert_emoticon,
color: Colors.amber,
size: 40,
),
// Icon Butoon to delete value at certain index
trailing: IconButton(
icon: Icon(
Icons.delete,
color: Colors.red,
),
onPressed: () {
delItem(index);
},),
// Setting title to ListTile
title: Text(
'Title of ${list[index]}',
),
// Setting subtitle to ListTile
subtitle: Text('Subtitle of ${list[index]}'),
),
),
);
},
),
// Floating Action Button to add values into the list
floatingActionButton: FloatingActionButton(
backgroundColor: Colors.red,
child: Icon(Icons.add),
onPressed: addItem,
),);}}

Status Bar

// Import Services Package
import 'package:flutter/services.dart'; 

void main() {
	// Hide Status bar and Bottom Navigation Bar
    SystemChrome.setEnabledSystemUIOverlays([]);
}

Lock Orientation

// Import library
import 'package:flutter/services.dart';
  // Add this into your main()
  await SystemChrome.setPreferredOrientations([
	// Locks Device orientation to always potrait
    DeviceOrientation.portraitUp,
  ]);

Loading Indicator

class SomeWidget extends StatefulWidget {
  @override
  _SomeWidgetState createState() => _SomeWidgetState();
}

class _SomeWidgetState extends State<SomeWidget> {
  Future future;

  @override
  void initState() {
    future = Future.delayed(Duration(seconds: 1));
    super.initState();
  }

  @override
  Widget build(BuildContext context) {
    return FutureBuilder(
      future: future,
      builder: (context, snapshot) {
        return snapshot.connectionState == ConnectionState.done
            ? Text('Loaded')
            : CircularProgressIndicator();
      },
    );
  }
}

Show Dialog Alert

// ShowDialog Builtin Function
showDialog<void>(
  context: context,
  barrierDismissible: false,
  builder: (BuildContext context) {
    return AlertDialog(
      title: Text('Alert Title'),
      content: Text('My Alert Msg'),
      actions: <Widget>[
        FlatButton(
          child: Text('Ask me later'),
          onPressed: () {
            print('Ask me later pressed');
            Navigator.of(context).pop();
          },
        ),
        FlatButton(
          child: Text('Cancel'),
          onPressed: () {
            print('Cancel pressed');
            Navigator.of(context).pop();
          },
        ),
        FlatButton(
          child: Text('OK'),
          onPressed: () {
            print('OK pressed');
            Navigator.of(context).pop();
          },
        ),
      ],
    );
  },
);

Form

Import Get from Pub

dependencies:
  get:

Generate GlobalKey for the form validation

GlobalKey<FormState> key = GlobalKey<FormState>();

Call this function where to show popup

  Get.bottomSheet(
    BottomSheet(
      onClosing: () => Get.back(),
      builder: (context) {
        return Form(
          key: key,
          child: SingleChildScrollView(
            child: Column(
              mainAxisSize: MainAxisSize.min,
              children: <Widget>[
                Row(
                  mainAxisAlignment: MainAxisAlignment.spaceBetween,
                  children: [
                    IconButton(
                      icon: Icon(Icons.close),
                      onPressed: () => Get.back(),
                    ),
                    Text(
                      'Form Title here',
                      style: GoogleFonts.pacifico(
                        textStyle: TextStyle(fontSize: 22.0),
                      ),
                    ),
                    IconButton(
                      icon: Icon(Icons.check),
                      onPressed: () {
                        if (key.currentState.validate()) {
                          // Get.to();
                          key.currentState.save();
                          Get.close(0);
                          Get.snackbar(
                              'Done', 'Data is submitted Successfully!',
                              snackPosition: SnackPosition.BOTTOM);
                        }
                      },
                    ),
                  ],
                ),
                TextFormField(
                  maxLength: 30,
                  keyboardType: TextInputType.name,
                  //  inputFormatters: [FilteringTextInputFormatter.digitsOnly],
                  decoration: InputDecoration(
                    prefixIcon: Icon(Icons.person_sharp),
                    helperText: 'i.e Usama Sarwar',
                    labelText: 'Full Name',
                  ),
                  validator: (_val) {
                    if (_val.isEmpty) {
                      return '*Required';
                    } else {
                      return null;
                    }
                  },
                  onChanged: (_val) {
                   // Save _val in some variable
                  },
                )
              ],
            ),
          ),
        );
      },
    ),
    isScrollControlled: true,
  );

Download Flutter Capsule source code on GitHub