10 Essential Flutter Widgets for Building High-Performance Flutter Apps.

Flutter widgets and application development

Lets get into what a Widget is? A widget is a basic element of the user interface that can be anything from a button, text, image, or layout. Everything in a Flutter app is a widget, including the app itself. As we have mentioned in the previous article, Flutter is a free software tool that helps people create mobile apps for iOS, Android, and website. Google made it using a computer language called “Dart“. It lets you make apps that run quickly and look good. If you’re new to Flutter, it’s important to learn the basics of how to use it.

Flutter provides a rich set of pre-built widgets for common UI elements, such as buttons, text fields, and progress indicators, as well as more complex widgets for creating flexible layouts, such as rows, columns, grids, and stacks.

Widgets in Flutter are similar to building blocks that can be arranged and combined to create the desired layout and behavior of the app. Widgets can be either Stateful or Stateless. A stateful widget can be modified, such as when a user interacts with it, while a stateless widget does not change after being rendered on the screen.

Developers can also create their own custom widgets by combining existing widgets and adding their own custom behavior. This allows for a high degree of customization and flexibility when building Flutter apps. We’ll explore the Flutter widget system, its architecture, and the different types of widgets.

Flutter Widget Architecture

At the heart of Flutter’s widget system is the concept of a widget tree. A widget tree is a hierarchical representation of the UI, where each element is a widget. Widgets can be thought of as building blocks of the user interface, which can be composed and reused to create complex UIs. The widget tree consists of two types of nodes.

a. Stateless Widgets

These widgets are immutable, meaning that their properties cannot change once they are created. They only depend on their configuration and do not hold any internal state. Examples include Text, Icon, and IconButton.

A basic stateless widget structure in Flutter looks something like this:

class Widget extends StatelessWidget {
  const Widget({Key? key}) : super(key: key);

  @override
  Widget build(BuildContext context) {
    return const Placeholder();
  }
}

b. Stateful Widgets

These widgets can maintain mutable state over their lifetime. They store state information in a separate State object, which is created by the createState() method. Examples include CheckBox, TextField, and Slider.

A basic stateful widget structure in Flutter looks something like this:

class Widget extends StatefulWidget {
  const Widget({Key? key}) : super(key: key);

  @override
  State<Widget> createState() => _WidgetState();
}

class _WidgetState extends State<Widget> {
  @override
  Widget build(BuildContext context) {
    return const Placeholder();
  }
}

Inherited Widgets

Inherited widgets are a special type of widget that can store data that is accessible by their descendants. They can efficiently propagate information down the widget tree and allow for easy access to shared resources like themes, localizations, and data.

To understand Inherited widget in more depth let’s take a look at a real world example.

import 'package:flutter/material.dart';

// Define the data you want to share
class MyData {
  final int value;
  MyData(this.value);
}

// Define the InheritedWidget that holds the shared data
class MyInheritedWidget extends InheritedWidget {
  final MyData data;

  MyInheritedWidget({required this.data, required Widget child})
      : super(child: child);

  // Update function
  static MyInheritedWidget of(BuildContext context) =>
      context.dependOnInheritedWidgetOfExactType<MyInheritedWidget>()!;

  @override
  bool updateShouldNotify(MyInheritedWidget oldWidget) =>
      oldWidget.data.value != data.value;
}

// Define a widget that uses the shared data
class MyWidget extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    final data = MyInheritedWidget.of(context).data;

    return Text("Value is: ${data.value}");
  }
}

// Define the top-level widget that sets up the shared data
class MyApp extends StatefulWidget {
  @override
  _MyAppState createState() => _MyAppState();
}

class _MyAppState extends State<MyApp> {
  MyData data = MyData(42);

  @override
  Widget build(BuildContext context) {
    return MyInheritedWidget(
      data: data,
      child: MaterialApp(
        home: Scaffold(
          appBar: AppBar(
            title: Text("Inherited Widget Example"),
          ),
          body: MyWidget(),
        ),
      ),
    );
  }
}

In this example, we first define the data we want to share using an ordinary Dart class MyData.

Next, we define an InheritedWidget called MyInheritedWidget that holds an instance of MyData. The MyInheritedWidget has two methods: updateShouldNotify and of. The updateShouldNotify method is called to determine whether to rebuild widgets that depend on the MyInheritedWidget. In this case, we compare the new and old MyData values to determine if a rebuild is necessary. The of method is used to obtain an instance of MyInheritedWidget from the widget tree.

We also define a simple widget called MyWidget that uses the shared data. In this case, we obtain an instance of MyData using the of method, and use it to display a value.

Finally, we define a top-level widget called MyApp that sets up the shared data. In this example, we create an instance of MyData with a value of 42, and wrap the MyInheritedWidget around the MaterialApp widget.

When the app is run, the MyWidget widget will automatically rebuild whenever the shared MyData object changes.

Stateful Widget Lifecycle

Stateful widgets have a lifecycle that goes through several stages, including creating the state object, building the widget, updating the widget, and disposing of the state object.

a. createState(): Called when the framework inflates the widget, it returns a new State object.

b. initState(): Called when the state object is created, it is used for initializing data or starting animations.

c. didUpdateWidget(): Called when the parent widget changes its configuration, it is used to update the state object accordingly.

d. build(): Called whenever the framework needs to rebuild the widget, it returns a new widget tree based on the current state.

e. dispose(): Called when the state object is removed from the tree, it is used for cleaning up resources, such as animations or streams.

GlobalKey

GlobalKeys are special keys that can uniquely identify a widget across the entire widget tree. They are used to access the state of a widget from anywhere in the application or to move a widget from one part of the tree to another while preserving its state.

To understand the GlobalKey also in more depth let’s have a real world example.

class MyWidget extends StatefulWidget {
  @override
  _MyWidgetState createState() => _MyWidgetState();
}

class _MyWidgetState extends State<MyWidget> {
  final GlobalKey<ScaffoldState> _scaffoldKey = GlobalKey<ScaffoldState>();

  void _showSnackBar() {
    final snackBar = SnackBar(content: Text('Hello, world!'));
    _scaffoldKey.currentState!.showSnackBar(snackBar);
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      key: _scaffoldKey,
      body: Center(
        child: ElevatedButton(
          onPressed: _showSnackBar,
          child: Text('Show Snackbar'),
        ),
      ),
    );
  }
}

In this example, we are using a GlobalKey to access the ScaffoldState of a Scaffold widget from within a child widget.

First, we declare a GlobalKey object _scaffoldKey of type GlobalKey<ScaffoldState>. Then, we set the key property of the Scaffold widget to this key.

In the _showSnackBar method, we use the _scaffoldKey to access the currentState of the Scaffold, and then call the showSnackBar method on it to display a SnackBar.

This is just one example of how you can use a GlobalKey in Flutter to access the state of a widget from a child widget. GlobalKey can also be used for other purposes, such as accessing the position of a widget on the screen or keeping track of the focus of a particular widget.

Layout Widgets

Layout widgets help in arranging and aligning other widgets within the application. Examples of layout widgets include Container, Row, Column, Stack, and GridView.

Row

Row is a widget that arranges its children in a horizontal line. Here’s an example:

Row(
  mainAxisAlignment: MainAxisAlignment.spaceEvenly,
  children: <Widget>[
    Text('Hello'),
    Text('World'),
    Text('!'),
  ],
)

In this example, we create a Row widget with three Text widgets as its children. We also specify the mainAxisAlignment property to evenly space the children along the main axis.

Column

Column is a widget that arranges its children in a vertical line. Here’s an example:

Column(
  mainAxisAlignment: MainAxisAlignment.center,
  children: <Widget>[
    Text('Hello'),
    Text('World'),
    Text('!'),
  ],
)

In this example, we create a Column widget with three Text widgets as its children. We also specify the mainAxisAlignment property to center the children along the main axis.

Container

Container is a widget that provides a rectangular visual element. Here’s an example:

Container(
  width: 100,
  height: 100,
  color: Colors.blue,
  child: Center(
    child: Text('Hello, world!'),
  ),
)

In this example, we create a Container widget with a width and height of 100, a blue background color, and a centered Text widget as its child.

ListView

ListView is a widget that displays a scrolling list of widgets. Here’s an example:

ListView(
  children: <Widget>[
    ListTile(
      leading: Icon(Icons.favorite),
      title: Text('Favorite'),
    ),
    ListTile(
      leading: Icon(Icons.music_note),
      title: Text('Music'),
    ),
    ListTile(
      leading: Icon(Icons.videocam),
      title: Text('Videos'),
    ),
  ],
)

In this example, we create a ListView widget with three ListTile widgets as its children. Each ListTile has an icon and a title.

These are just a few examples of the many layout widgets available in Flutter. You can customize these widgets and combine them in different ways to create complex layouts for your apps.

In a nutshell

At the core of Flutter’s UI development process lies its innovative widget system, which provides a straightforward and effective means for combining and reusing various UI components. This feature establishes Flutter as a versatile and powerful tool well-suited for constructing modern applications across different platforms. As developers gain a deeper understanding of the widget architecture, the lifecycle of widgets, and the diverse range of widgets available, they are better equipped to create visually appealing and high-performing user interfaces with ease. This enhanced capability ultimately contributes to an overall superior user experience and more efficient development workflows.

. . .

Website: https://www.etechviral.com

LinkedIn eTechViral: https://www.linkedin.com/company/etechviral/?viewAsMember=true

YouTube: https://www.youtube.com/channel/UCO6gMNHYhRqyzbskNh4gG_A

eTechViral Instagram: https://www.instagram.com/etechviral/

Leave a Reply

You may like