Can we build any app with flutter

Yes, we can build any app with Flutter. Not only that, we can build that app in many ways. Flutter SDK is so versatile that it gives us plenty of choices. We need to decide what will suit us best.

In our last two sections, consecutively we’ve built two simple Flutter applications. Both flutter applications are a simple Blog that we’ve built with the help of Provider package. 

However, although we’ve built the same flutter application, yet they are different in approach.

This time we’re going to build the same flutter application using third approach.

Why?

Because you can compare those applications and learn how to solve the same problem using different approaches.

This flutter application, which is a blog, only displays a few clickable posts on home page. Consequently, we can click any post and read that post in detail on another screen.

In our first approach, we’ve passed the provided value through class constructors. As a result, we need to pass around a lot of data across our app.

However, we can reduce the boilerplate and manage the same thing by using for loop in proper place. To tell you frankly, we can do many things in Flutter with one single package Provider.

Just for little recapitulation let us first remember what Provider is. We can use Provider package in Flutter for many purposes, that also includes passing a global style or data across the flutter app. 

Certainly, we can pass the provided value through child constructors. But, as we just told, we need to be careful about not making it too much.

Before we start building the blog app using for loop, I strongly recommend to compare these three GitHub repositories that build the same Flutter application; but in different way.

Let us put the Providers above the root app.

import 'package:flutter/material.dart';
import 'package:provider/provider.dart';
import 'model/global_theme.dart';
import '/model/blog_post.dart';
import 'view/home.dart';

void main() {
  runApp(
    /// Providers are above [Root App] instead of inside it, so that tests
    /// can use [Root App] while mocking the providers
    MultiProvider(
      providers: [
        ChangeNotifierProvider(create: (_) => GlobalTheme()),
        Provider<List<BlogPost>>(
          create: (context) => blogPosts,
        )
      ],
      child: const Home(),
    ),
  );
}

The above code shows that we have two data model classes in place. As a result, the providers will provide the value from these two objects.

So it’s better to take a look at the first model class which defines the custom ThemeData object. It will basically manage a custom theme across the whole flutter application.

import 'package:flutter/material.dart';

class GlobalTheme with ChangeNotifier {
  final globalTheme = ThemeData(
    primarySwatch: Colors.deepOrange,
    textTheme: const TextTheme(
      bodyText1: TextStyle(
        fontSize: 22,
      ),
      bodyText2: TextStyle(
        color: Colors.blue,
        fontSize: 18,
        fontWeight: FontWeight.bold,
      ),
      caption: TextStyle(
        fontSize: 16,
        fontWeight: FontWeight.bold,
        fontStyle: FontStyle.italic,
      ),
      headline1: TextStyle(
        color: Colors.deepPurple,
        fontSize: 50,
        fontFamily: 'Allison',
      ),
      headline2: TextStyle(
        color: Colors.deepOrange,
        fontSize: 30,
        fontWeight: FontWeight.bold,
      ),
    ),
    appBarTheme: const AppBarTheme(
      backgroundColor: Colors.amber,
      // This will control the "back" icon
      iconTheme: IconThemeData(color: Colors.red),
      // This will control action icon buttons that locates on the right
      actionsIconTheme: IconThemeData(color: Colors.blue),
      centerTitle: false,
      elevation: 15,
      titleTextStyle: TextStyle(
        color: Colors.deepPurple,
        fontWeight: FontWeight.bold,
        fontFamily: 'Allison',
        fontSize: 40,
      ),
    ),
  );
}

Next, comes our Blog class where we have created three separate blog posts. Let us see the code.

import 'package:flutter/foundation.dart';

class BlogPost with ChangeNotifier {
  final String id;
  final String title;
  final DateTime date;
  final String content;

  BlogPost({
    required this.id,
    required this.title,
    required this.date,
    required this.content,
  });
}

final blogPosts = [
  BlogPost(
    id: 'b1',
    title: 'First Post',
    date: DateTime(2020, 1, 2),
    content: 'This is First post. So it is better not to write more.',
  ),
  BlogPost(
    id: 'b2',
    title: 'Second Post',
    date: DateTime(2020, 2, 15),
    content: 'This is Second post. Sorry for the delay in posting.',
  ),
  BlogPost(
    id: 'b3',
    title: 'Third Post',
    date: DateTime(2020, 3, 25),
    content: 'This is Third post. Again delay! Why? Because Words evade me.',
  ),
];

Now we’re in a position to provide values to any position in our widget tree. Our first child widget is Home.

import 'package:flutter/material.dart';
import 'package:provider/provider.dart';
import '/model/global_theme.dart';
import 'home_page.dart';

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

  @override
  Widget build(BuildContext context) {
    final ThemeData globalTheme = Provider.of<GlobalTheme>(context).globalTheme;
    return MaterialApp(
      title: 'Flutter Demo',
      theme: globalTheme,
      home: const HomePage(),
    );
  }
}

We’ve set our default theme and provider has provided the custom ThemeData object. As a result, we can now use Theme.of(context) to apply the custom theme across the whole flutter application.

The next child is HomePage.

We It will be our home page or screen that shows all the blog titles. They are clickable. So that we can click any blog title and read the entire text in another screen.

import 'package:flutter/material.dart';
import 'package:provider/provider.dart';
import 'package:intl/intl.dart';
import '/model/blog_post.dart';

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

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text(
          'Blog Home Page',
          style: Theme.of(context).appBarTheme.titleTextStyle,
        ),
      ),
      body: const HomeBody(),
    );
  }
}

Now, we’re building the widget tree, and provider is providing the necessary value to any child of the widget tree. Therefore, we can style the AppBar of the home page here with our custom theme.

Next child is HomeBody that will show the body section of home page where we will see the clickable blog titles.

To make it happen, we need to provide exact blog object to the Home body widget.

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

  @override
  Widget build(BuildContext context) {
    final blogs = Provider.of<List<BlogPost>>(context);
    return Center(
      child: Column(
        children: [
          Container(
            margin: const EdgeInsets.all(5),
            padding: const EdgeInsets.all(5),
            child: Text(
              'Blog by Clumsy Coder',
              style: Theme.of(context).textTheme.headline2,
            ),
          ),
          Container(
            margin: const EdgeInsets.all(5),
            padding: const EdgeInsets.all(5),
            child: Text(
              'I am a clumsy coder trying to write decent code, and '
              'fiction.'
              ' But there is a friction. '
              'So, I avoid proper diction.',
              style: Theme.of(context).textTheme.headline1,
            ),
          ),
          Flexible(
            child: GridView.builder(
              padding: const EdgeInsets.all(10.0),
              itemCount: blogs.length,
              itemBuilder: (ctx, i) => ChangeNotifierProvider.value(
                value: blogs[i],
                child: InkWell(
                  onTap: () {
                    Navigator.push(
                      context,
                      MaterialPageRoute(
                        builder: (context) => BlogDetail(
                          post: blogs[i],
                        ),
                      ),
                    );
                  },
                  child: Text(blogs[i].title),
                ),
              ),
              gridDelegate: const SliverGridDelegateWithFixedCrossAxisCount(
                crossAxisCount: 1,
                childAspectRatio: 20 / 2,
                crossAxisSpacing: 2,
                mainAxisSpacing: 2,
              ),
            ),
          )
        ],
      ),
    );
  }
}

Although the code looks lengthy, still it is quite simple.

Firstly, we’ve applied the custom Theme to style the Text. Just like the snippet below.

child: Text(
              'Blog by Clumsy Coder',
              style: Theme.of(context).textTheme.headline2,
            ),

Secondly, our main challenge was to display the all blog post titles on the page. So we’ve used ChangeNotifierProvider value constructors that goes very well with GridView builder constructor.

Why so?

Because, according the length of the items, GridView builds its child items. Moreover, ChangeNotifierProvider value constructor works on the principle of items’ index.

 child: GridView.builder(
              padding: const EdgeInsets.all(10.0),
              itemCount: blogs.length,
              itemBuilder: (ctx, i) => ChangeNotifierProvider.value(
                value: blogs[i],
....
// code is incomplete

As a result, we can now see the output on the screen with the blog titles.

Flutter blog app with provider home page
Flutter blog app with provider home page

Next, we should work on building a Material App route that will take us to the single blog post page which is the next widget in our widget tree.

class BlogDetail extends StatelessWidget {
  final BlogPost post;
  const BlogDetail({
    Key? key,
    required this.post,
  }) : super(key: key);

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text(
          'Blog Page',
          style: Theme.of(context).appBarTheme.titleTextStyle,
        ),
      ),
      body: Center(
        child: ListView(
          children: [
            Container(
              margin: const EdgeInsets.all(5),
              padding: const EdgeInsets.all(5),
              child: Text(
                post.title,
                textAlign: TextAlign.left,
                style: Theme.of(context).textTheme.headline1,
              ),
            ),
            Container(
              margin: const EdgeInsets.all(5),
              padding: const EdgeInsets.all(5),
              child: Text(
                post.content,
                textAlign: TextAlign.left,
                style: Theme.of(context).textTheme.bodyText1,
              ),
            ),
            Container(
              margin: const EdgeInsets.all(5),
              padding: const EdgeInsets.all(5),
              child: Text(
                DateFormat('d MMMM y').format(post.date),
                style: Theme.of(context).textTheme.bodyText2,
              ),
            ),
          ],
        ),
      ),
    );
  }
}

As we click any title of the post, the single page blog post page opens up and shows that post in detail.

Flutter blog app with provider single blog page
Flutter blog app with provider single blog page

Certainly, it’s a matter of choice which route you’ll take. However, we’ve built a similar flutter application with the help of Provider package. In the next section, we’ll try to add blog posts dynamically and display the posts on the screen.

So stay tuned and happy fluttering. To get the full code snippet please visit the respective GitHub repository.

What Next?

Books at Leanpub

Books in Apress

My books at Amazon

GitHub repository

Technical blog

Twitter

Comments

One response to “Can we build any app with flutter”

  1. […] Flutter is extremely beginner friendly software development kit, or framework. All you need to have a basic idea about object oriented programming and Dart language which acts […]

Leave a Reply