Master Flutter Essentials: Intensify Powerful UIs

We are here today when flutter is growing more than ever. It still requires the community to support its seamless functioning. Learning it now in this crunch time is like striking the iron while it’s hot!

Aditya Patnaik
Flutter Community
Published in
9 min readOct 1, 2019

--

This is the second edition in the quest to become a Master Flutter developer. In the last article, we covered the basics of flutter to get you started/Inspired. This time we’ll dive deeper into the Flutter Essentials to create marvelous production-ready apps.

Let’s get the ball rolling…

Dribble.com

WebView Widget

WebView Widget

Recipe

WebView Widget requires a dependency.

Add “webview_flutter: ^0.3.14” to the pubspec.yaml file under “dependencies:”

Hit Save.

pubspec.yaml Screenshot

Widget Signature

Key key,
onWebViewCreated, //invoked when webview is created
initialUrl,
javascriptMode:JavascriptMode.disabled,
javascriptChannels,
navigationDelegate,
gestureRecognizers,
onPageFinished,
debuggingEnabled:false,
userAgent,
initialMediaPlaybackPolicy:AutoMediaPlaybackPolicy.require_user_action_for_all_media_types,

Know-How

  • A WebView Widget is a container that can load webpages on demand.
  • Javascript could be enabled or disabled using javascript mode property.
  • A channel object is created for each javascript channel and made available for the code to access.
  • A new javascript channel takes effect only after the next page is loaded.
  • A postmessage can be called on that object using javascript.
JavascriptChannel(
name: 'Print',
onMessageReceived: (JavascriptMessage message) {
print(message.message);
});
  • A WebView always takes the complete form factor.
  • It’s impossible to decorate WebView’s fixed features.

BackDropFilter Widget

BackdropFilter(
filter: ImageFilter.blur(
sigmaX: 4.0, //controls the blur depth
sigmaY: 4.0,
),
child: Container(
color: Colors.black.withOpacity(0.0),
),
),
  • A backdropfilter must be used in a stack along with the child widget to be superimposed.
  • To position backdropfilter at a specific place, it’s recommended to use a Positioned Widget.
  • The sigmaX and sigmaY properties control the blur effect.

Implementation

WebView Widget

Container( 
child: WebView( initialUrl: 'https://flutter.dev/', javascriptMode: JavascriptMode.unrestricted,
), // WebView
), // Container

WebView with a Backdrop Filter.

WebView with BackDropFilter
Stack(
children: <Widget>[
Container(
height: 400.0,
width: 400.0,
child: WebView(
initialUrl: 'https://www.google.com/',
javascriptMode: JavascriptMode.unrestricted,
),
),
Positioned.fill(left:200.0,right: 100.0,top: 100.0,bottom: 150,
child: BackdropFilter(
filter: ImageFilter.blur(sigmaX: 4.0,sigmaY: 4.0,),
child: Container(color: Colors.black.withOpacity(0.0),),),),
],),

Out in the open

  • How to open webpages in a listview?
  • How to Webview in fullscreen?
  • How to implement a backdropfilter with blur effect?

PageView Widget

PageView with pageSnapping

Widget Signature

PageController _controller = PageController();
Key key,
scrollDirection:Axis.horizontal,
reverse:false,
PageController controller: _controller,
physics:BouncingScrollPhysics()
pageSnapping:true,
onPageChanged,
List<Widget> children:const <Widget>[],
dragStartBehavior:DragStartBehavior.start,

Know-How

  • A PageView creates a list of scrollable pages.
  • scrollDirection property specifies the axis across which the PageView scrolls.
  • The scrollPhysics property defines the interaction with the widget.
  • Bouncing Scroll Physics in a PageView looks like this.
  • The pageSnapping property when set creates a “swipe resistance” effect.
  • A WebView retains it’s shaping irrespective of what shape its parent takes.(Even if it’s inside a card widget thats further placed in a PageView)

How to control a PageView?

  • Use a Page Controller!
PageController({initialPage = 0,keepPage = true,viewportFraction = 1.0,})

A Page Controller has the following functions.

animateToPage(int page, {Required duration,Required curve,})
previousPage({ Required duration, Required curve })
nextPage({ Required duration, Required curve })
jumpToPage(int page)

Implementation

How to use a PageController and Transform Widget to apply transitions?

PageView with Transform

PageView with WebView

On the same page

  • How to create scrollable screens?
  • How to use multiple WebViews in fullscreen?
  • What is Bouncing Scroll Physics?
  • How to create a list of WebViews using PageView?
  • How to use a controller in a PageView?
  • Apply a transition to the PageView.

BottomSheet Widget

Widget Signature

Required BuildContext context,             //context != null
Required WidgetBuilder builder, //builder != null
Color backgroundColor,
double elevation,
ShapeBorder shape:RoundedRectangleBorder(borderRadius:BorderRadius.circular(30.0),),
isScrollControlled:false, //if set,bottomsheet goes fullscreen.
Material Guidelines

What Material Design Principles Say?

Material Design Specs for BottomSheet

Know-How

  • A bottomsheet widget prevents the user from interacting with the rest of the UI while exposing additional options.
  • Set the isScrollControlled property to true to display the bottomsheet in fullscreen.
  • The isScrollControlled property expects a scrollable child widget. (Ex: ListView).

To know more:

Implementation

Smooth sailing

  • How to make a bottomsheet scrollable?
  • How to build a fullscreen bottomsheet?
  • How does isScrollControlled property works?
  • How to use a GridView inside a bottomsheet?

TabBar Widget

Custom Card Indicator

Widget Signature

Key key,
tabs: <Widget>[
Tab(text: 'Home',icon: Icon(Icons.home),),
Tab(text: 'Videos',icon: Icon(Icons.featured_video),),
Tab(text: 'Favourites',icon: Icon(Icons.favorite,color: Colors.pink,),),
Tab(text: 'Upload',icon: Icon(Icons.file_upload),),
],
controller,
isScrollable = false, //Default
indicatorWeight = 2.0,
indicatorSize,
indicatorPadding = EdgeInsets.zero,
labelPadding: EdgeInsets.symmetric(vertical: 10),
labelStyle: TextStyle(fontSize: 18.0),
labelColor: Colors.blueAccent,
unselectedLabelColor: Colors.white,
unselectedLabelStyle: TextStyle(fontSize: 14),
indicator: ShapeDecoration( // if indicator is set, indicatorWeight,indicatorPadding, indicatorColor are ignored
color: Colors.white,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(30)
),
),
dragStartBehavior = DragStartBehavior.start,
onTap(){}
Material Guidelines

Know-How

  • TabBar Widget helps to create tabs, each having its page to maintain.
  • A TabController must be provided to take control of the tabs.
  • Alternatively, use a DefaultTabController.
  • However, to use a DefaultTabController, a Scaffold should be a child to the controller.
Widget build(BuildContext context) {
return Scaffold(
body: DefaultTabController(
length: 4,
child: Scaffold(
appBar: AppBar(
title:Center( child:Text('TabBar'),),
bottom: _tabBar(),
),
.
.
.
  • The length of the list must match the number of items in the TabBarView.
  • If isScrollable property is true then each tab will only be as wide as it’s label. Otherwise, the tabs expand to take an equal share of the available space.
  • Setting the indicator property to UnderlineTabIndicator enables the Underlined tab indicator.
indicator: UnderlineTabIndicator(
borderSide: BorderSide(
width: 2.0,
color: Colors.white,
)
),
Underlined Tab Indicator

Implementation

In a nutshell

  • How to make a custom tabbar label?
  • How to use the default underline label indicator?
  • How to print the label text on to the tabview?
  • What is a DefaultTabController?
  • How is tabbar different from TabBarView?

BottomNavigationBar Widget

Bottom Navigation Bar

Widget Signature

Key key,
Required items = [ BottomNavigationBarItem(icon,title) //title!=null
BottomNavigationBarItem(icon,title) //title!=null ], //(items.length >= 2)
onTap(){},
currentIndex = 0,//(0<=currentIndex && currentIndex < items.length)
elevation = 8.0, //elevation!=null
BottomNavigationBarType = BottomNavigationBarType.shifting,
Color fixedColor,
backgroundColor,
iconSize = 24.0, ////iconSize!=null
selectedItemColor,
unselectedItemColor,
selectedIconTheme = const IconThemeData(),
unselectedIconTheme = const IconThemeData(),
selectedFontSize = 14.0,
unselectedFontSize = 12.0,
selectedLabelStyle,
unselectedLabelStyle,
showSelectedLabels = true,
bool showUnselectedLabels,
Material Guidelines

What Material Design Guidelines Say?

Know-How

  • A Stateful Widget uses a setState function to keep track of the BottomNavigationBarItems when selected.
onTap: (index){
setState(() {
current = index;
switch(current){
case 0:
_data = "Home";
break;
case 1:
_data = "Cart";
break;
}
});
},
  • The item’s backgroundColor will be used as BottomNavBar’s backgroundColor if the type property is set to BottomNavigationBarType.shifting.

The Design implemented below doesn’t comply with the Material Guidelines. It has been made only to show diverse ways to approach such Widgets.

Type set to shifting
  • If the BottomNavigationBarType is set to”fixed”, then the labels can be seen by default.
  • However, if the BottomNavigationBarType is set to “shifting” then the unselected labels of the BottomNavBaritems cannot be seen.

Implementation

Raise the bar

  • How to hide the unselected item text in a BottomNavigationBar?
  • SelectedItemColor property doesn’t work in BottomNavigationBar?
  • How to make a custom BottomNavBarItem?
  • How to align a CustomBottomNavBar item in a row?

DropDownButton Widget

Widget Signature

Key key,
Required this.items,
value,
hint,
disabledHint,
Required this.onChanged,
elevation = 8,
style,
underline,
icon,
iconDisabledColor,
iconEnabledColor,
iconSize = 24.0,
isDense = false,
isExpanded = false,
Material Guidelines

Know-How

  • Each item in the DropDown list is of the type DropdownMenuItem<T>.
DropdownMenuItem<String>(        // <T> = <String>
value: "1",
child: Row(
crossAxisAlignment: CrossAxisAlignment.center,
mainAxisAlignment: MainAxisAlignment.spaceAround,
children: <Widget>[
Icon(Icons.add_alarm),
Text('Flutter 1',style: TextStyle(color: Colors.black),)
],
)
),
  • The letter ‘T’ represents the data type of the DropDown item.
  • A DropDownList is built using a DropDownButton Widget, whose items should be of the type DropDownMenuItem.
  • The underline property could be used to underline a selected DropDownItem.
underline: Container(          height: 2,          color: Colors.deepPurpleAccent,

),
DropDown with Underline
  • The onChanged function is used to update the state of the DropDown every time a new option is selected.
onChanged: (value){
setState(() {
_value = value;
});
  • To learn everything about how to build an awesome looking DropDown.

Visit:

Implementation

Can you see through?

  • How to build a DropDown?
  • How to underline the selected DropDownlistItem?
  • How to use the map function to implement a DropDownButton Widget?

Drawer Widget

Widget Signature

Key key,elevation:16.0,child,semanticLabel: MaterialLocalizations.drawerLabel,
Material Guidelines

Know-How

  • The semantic label property is used by the access frameworks to trigger transitions on the opening and closing of the drawer.
  • Scaffold widget creates the Drawer controller automatically.
// Signature of a Drawer Controller
GlobalKey key,
Required child,
Required alignment,
drawerCallback, //called when the drawer is opened or closed
dragStartBehavior:DragStartBehavior.start,
scrimColor,
edgeDragWidth,
  • Drawer takes the shape of a gesture detector to detect swipes when closed.
  • A Drawer Header typically describes the user account information.
DrawerHeader(     child: Text('Drawer Header',style: TextStyle(
color: Colors.white,fontSize: 32.0,
),
),
decoration: BoxDecoration(
color: Colors.blueGrey,
),
),
  • Learn to build a Drawer as per the material guidelines from here.

Visit:

Implementation

Easy come, easy go

  • What controls the Drawer Movement?
  • How to build a Drawer with a list of options?
  • What’s a Drawer Header?

Stepper Widget

Widget Signature

Key key,
Required steps: [
Step( title,content,subtitle,isActive,state),
Step( title,content,subtitle,isActive,state),
Step( title,content,subtitle,isActive,state),
];
physics,
type:StepperType.vertical,
currentStep = 0,
onStepTapped,
onStepContinue,
onStepCancel,
controlsBuilder,

Know-How

  • The Stepper widget is a fancy one, it breaks a compound task into a sequence of sub-tasks and lays it on the UI, beautifully
  • However, as per the Material Guidelines, a stepper widget should not be used for short forms or multiple times on a single screen.
  • There are two kinds of Steppers. Vertical and Horizontal.
  • Here is how a Standard Stepper Widget can be Designed. (As per the Material Guidelines)
Stepper Design
  • On pressing the continue-button the “onStepContinue” callback is called.
  • On pressing the cancel-button the “onStepCancel” callback is called.
onStepCancel: cancel(){
setState(() {
if(current>0){
goTo(current-1);
}
});
},
onStepContinue: next(){
setState(() {
if(current<steps.length-1){
goTo(current+1);
}
});
},
  • To know more about the Material specification concerning the Stepper Widget. See here.

Visit:

Implementation

No-brainer

  • How to build a Stepper Widget?
  • How to build a horizontal Stepper?
  • How to add multiple textFields in a single step in Stepper Widget?

With Eternal Gratitude,

I am so very thankful for your time. Let me know if I can help.

Thanks for considering this. You’re the best!

--

--

Aditya Patnaik
Flutter Community

Simple Living, High Thinking | Full-Stack Developer | Tech Enthusiast | Feel free to reach out to me.