UI Design: Sparkline Bar Chart in Flutter (YouTube Studio)
Tags: flutter
Published: 2020-04-27 15:32:47

---
title: UI Design: Sparkline Bar Chart in Flutter (YouTube Studio)
published: true
date: 2020-04-20 17:45:49 UTC
tags: flutter
canonical_url: 
---

 ![UI Design: Sparkline Bar Chart in Flutter (YouTube Studio)](https://developer.school/content/images/2020/04/UI-1.png)

In this article we're going to look at how to replicate the Sparkline Bar Chart as seen in the Realtime Views section of the YouTube Studio application. This is quite a common chart and represents datasets at a small scale, allowing you to see results at a glance.

#### Video

Prefer to watch a video? Here's one I made for this article:

<iframe width="459" height="344" src="https://www.youtube.com/embed/6fkWxDdUfY4?feature=oembed" frameborder="0" allow="accelerometer; autoplay; encrypted-media; gyroscope; picture-in-picture" allowfullscreen></iframe>

Here's an example of the UI we'll be making in comparison to the YouTube Studio application:

![UI Design: Sparkline Bar Chart in Flutter (YouTube Studio)](https://developer.school/content/images/2020/04/UI.png)

> NOTE: I'm still learning how to best take advantage of the `CustomPainter` and `Canvas` with Flutter and I'm documenting my learning here. I'd love your feedback!

### Project Setup

With that in mind - let's make a new Flutter project in the terminal:

```
# New Flutter project
$ flutter create flutter_sparkline

# Open in VS Code
$ cd flutter_sparkline && code .
```

We'll then create a new page at `presentation/pages/home_page.dart` named `HomePage`:

```
import 'package:flutter/material.dart';

class HomePage extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: Center(
        child: Text("Hello, Flutter!"),
      ),
    );
  }
}
```

We can then update our `main.dart` accordingly:

```
import 'package:flutter/material.dart';
import 'package:flutter_sparkline/presentation/pages/home_page.dart';

void main() {
  runApp(MyApp());
}

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Sparkline',
      theme: ThemeData(
        visualDensity: VisualDensity.adaptivePlatformDensity,
        primaryColor: Colors.black,
      ),
      debugShowCheckedModeBanner: false,
      home: HomePage(),
    );
  }
}
```

### Building the Sparkline

In order to build our Sparkline Chart we're going to use the `CustomPaint` widget which takes a `CustomPainter` which we'll define as `SparklinePainter` at `lib/presentation/painters/sparkline_painter.dart`:

```
import 'dart:math';

import 'package:flutter/material.dart';

class SparklinePainter extends CustomPainter {
  List<num> data;
  Color color;
  
  SparklinePainter({@required this.data, this.color});

  @override
  void paint(Canvas canvas, Size size) {
    num index = 0;
    num barSize = size.width / data.length;
    num maxValue = data.reduce(max).toDouble();

    for (num point in data) {
      num barHeight = (size.height * point / maxValue).roundToDouble();
      
      _drawBar(
        canvas: canvas,
        left: barSize * index,
        top: size.height - barHeight,
        width: barSize,
        height: barHeight,
      );
      index++;
    }
  }

  _drawBar({Canvas canvas, num left, num top, num width, num height}) {
    Paint paint = Paint()
      ..color = color ?? Colors.red
      ..style = PaintingStyle.fill
      ..strokeWidth = 8.0;

    Rect rect = Rect.fromLTWH(left, top, width, height);

    canvas.drawRect(rect, paint);
  }

  @override
  bool shouldRepaint(CustomPainter oldDelegate) => true;
}
```

We can break the above down by the following steps:

1. We're getting our initial set-up data such as the `barSize` (depending on how many data points there are). We're also getting the `maxValue` from the `data` points passed in. This will be used to determine our `barHeight` in a moment.
2. For a particular list of numerical data (i.e. `[1, 2, 3, 4, 5]`), firstly, determine the `barHeight` from a `0-height` scale.
3. Then we're drawing a `Rect` on screen with our specified coordinates.
4. Finally, we're incrementing our `index` in order to move the next `Rect` along one.

Now that we've got our `SparklinePainter`, we can use this inside of our `SparklineChart` widget:

```
import 'dart:math';

import 'package:flutter/material.dart';
import 'package:flutter_sparkline/presentation/painters/sparkline_painter.dart';

class SparklineChart extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Container(
      height: 40,
      width: 100,
      child: CustomPaint(
        painter: SparklinePainter(
          color: Color(0xFF00a7cf),
          data: List.generate(
            40,
            (index) {
              Random rnd = Random();
              return rnd.nextInt(20) + 6;
            },
          ),
        ),
      ),
    );
  }
}

```

This currently generates some fake dummy data using `List.generate`, but feel free to swap out the `data` with some of your choosing.

### YouTube UI

Now all we need to do is update our `HomePage` with some crude UI code that represents the top of the YouTube Studio app:

```
import 'package:flutter/material.dart';
import 'package:flutter_sparkline/sparkline_chart.dart';

class HomePage extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return DefaultTabController(
      length: 5,
      child: Scaffold(
        appBar: buildAppBar(),
        backgroundColor: Colors.white.withOpacity(0.85),
        body: Column(children: [
          SizedBox(
            height: 8,
          ),
          buildRealtimeSparklineCard(),
        ]),
      ),
    );
  }

  Container buildRealtimeSparklineCard() {
    return Container(
      color: Colors.white,
      child: Padding(
        padding: const EdgeInsets.all(20.0),
        child: Row(
          mainAxisSize: MainAxisSize.max,
          mainAxisAlignment: MainAxisAlignment.spaceBetween,
          children: <Widget>[
            Column(
              mainAxisAlignment: MainAxisAlignment.center,
              crossAxisAlignment: CrossAxisAlignment.start,
              children: <Widget>[
                Text(
                  "Realtime views",
                  style: TextStyle(fontWeight: FontWeight.bold, fontSize: 16),
                ),
                SizedBox(
                  height: 6,
                ),
                Text(
                  "48 Hours • Estimated views",
                  style: TextStyle(color: Colors.black54, fontSize: 12),
                ),
                SizedBox(
                  height: 6,
                ),
                Text("6,500"),
              ],
            ),
            SparklineChart(),
          ],
        ),
      ),
    );
  }

  AppBar buildAppBar() {
    return AppBar(
      title: Row(
        mainAxisAlignment: MainAxisAlignment.spaceBetween,
        children: <Widget>[
          Text("Analytics", style: TextStyle(color: Colors.black)),
          Row(
            children: <Widget>[
              Container(
                padding: EdgeInsets.all(6),
                decoration:
                    BoxDecoration(color: Colors.grey, shape: BoxShape.circle),
                child: Text(
                  "24",
                  style: TextStyle(color: Colors.white, fontSize: 12),
                ),
              ),
              SizedBox(
                width: 14,
              ),
              CircleAvatar(
                maxRadius: 13,
                backgroundImage: NetworkImage(
                  "https://yt3.ggpht.com/a-/AOh14GhB7xAslx6hmlYqG9-NDLyRj8ycHFUn7ypBMXv52Q=s288-c-k-c0xffffffff-no-rj-mo",
                ),
              )
            ],
          )
        ],
      ),
      centerTitle: false,
      brightness: Brightness.light,
      leading: IconButton(
        icon: Icon(Icons.menu),
        onPressed: () {},
      ),
      bottom: PreferredSize(
        preferredSize: Size.fromHeight(40.0),
        child: Column(
          children: <Widget>[
            Divider(
              height: 2,
            ),
            Container(
              margin: EdgeInsets.only(left: 20),
              child: TabBar(
                isScrollable: true,
                indicatorColor: Colors.black,
                tabs: [
                  Tab(
                    child:
                        Text("OVERVIEW", style: TextStyle(color: Colors.black)),
                  ),
                  Tab(
                    child:
                        Text("REVENUE", style: TextStyle(color: Colors.black)),
                  ),
                  Tab(
                    child: Text("DISCOVERY",
                        style: TextStyle(color: Colors.black)),
                  ),
                  Tab(
                    child:
                        Text("AUDIENCE", style: TextStyle(color: Colors.black)),
                  ),
                  Tab(
                    child: Text("INTERACTIVE CONTENT",
                        style: TextStyle(color: Colors.black)),
                  ),
                ],
              ),
            ),
          ],
        ),
      ),
      iconTheme: IconThemeData(color: Colors.black),
      backgroundColor: Colors.white,
    );
  }
}

```

Here's the final results of our work:

![UI Design: Sparkline Bar Chart in Flutter (YouTube Studio)](https://developer.school/content/images/2020/04/Screenshot-2020-04-20-at-18.43.00.png)

### Summary

In this article we looked at how to create a Sparkline chart with the Flutter `CustomPainter`. I hadn't used the `CustomPainter` or Flutter `Canvas` before this, so it was a fun experiment!

I'd love to hear your thoughts on Twitter or in the comments.

Code for this article: [https://github.com/PaulHalliday/flutter\_sparkline](https://github.com/PaulHalliday/flutter_sparkline)