Creating an Analog Clock in Flutter: III

Philip Okonkwo
5 min readApr 2, 2018

--

The full code for the app can be found here. Other parts of the series can be found below:

Part I

Part II

Part IV

It is time to create the clock face and get it looking more like a clock.

Create a new file called clock_face.dart. Add the following code into it.

import 'package:flutter/material.dart';

class ClockFace extends StatelessWidget{
@override
Widget build(BuildContext context) {
return new Padding(
padding: const EdgeInsets.all(10.0),
child: new AspectRatio(
aspectRatio: 1.0,
child: new Container(
width: double.INFINITY,
decoration: new BoxDecoration(
shape: BoxShape.circle,
color: Colors.white,
),

child: new Stack(
children: <Widget>[
//dial and numbers go here


//centerpoint
new Center(
child: new Container(
width: 15.0,
height: 15.0,
decoration: new BoxDecoration(
shape: BoxShape.circle,
color: Colors.black,
),
),
),
//clock hands go here
],
),
),

),
);
}
}

What we have just done should be familiar and trivial to anyone who followed the last part of this series. We created a Padding widget with a padding of 10.0 on all sides and gave it a child that is an AspectRatio with a ratio of 1.0. The child of this aspect ratio is a Container widget we have made into a circular shape just like we did in the last part. The time we have made the circle white in color because it will be the face of our clock. The container widget itself has a Stack for a child. This Stack widget will help us stack up the clock dials, numbers as well as the hands of the clock in the future. For now its only child is just a small black circle in the middle of the white circle.

Go back to the clock_body.dart file we created in the last part. Import the clock_face.dart file we just created and modify the ClockBody widget to include the new ClockFace widget we just created.

The ClockBody widget now looks like this:

import 'dart:math';

import 'package:flutter/material.dart';
import 'package:clock/clock_face.dart';

class ClockBody extends StatelessWidget{

ClockBody();

@override
Widget build(BuildContext context) {
return new AspectRatio(
aspectRatio: 1.0,
child: new Stack(
children: <Widget>[
new Container(
width: double.INFINITY,
child: new CustomPaint(
painter: new BellsAndLegsPainter(),
),
),


new Container(
width: double.INFINITY,
decoration: new BoxDecoration(
shape: BoxShape.circle,
color: Colors.black,
boxShadow: [
new BoxShadow(
offset: new Offset(0.0, 5.0),
blurRadius: 5.0,
)
],
),

child: new ClockFace(),

)
]
)

);
}
}

And we get this:

We are getting there

Now back to the clock_face.dart file we are going to paint in the ticks as well as the numbers.

In the Stack inside the ClockFace widget add the following code:

//dial and numbers go here
new Container(
width: double.INFINITY,
height: double.INFINITY,
padding: const EdgeInsets.all(10.0),
child:new CustomPaint(
painter: new ClockDialPainter(clockText: ClockText.roman),
),
),

Again this is mostly familiar. We have created another Container widget whose width and height are as large as possible and since it is in a Stack which is itself contained in an AspectRatio widget, the width and height will be the same value. The Container as a padding of 10.0 on all sides and it has a child that is a CustomPaint. The painter for this is an instance of the ClockDialPainter class which we are going to create soon the same way we created the BellsAndLegsPainter in the last part. The ClockDialPainter class constructor will take a named parameter clockText that will help us choose whether to paint in the numbers as Arabic or Roman numerals.

Facial Make-Up

Unlike we did in the last part, we are going to create a separate file for the ClockDialPainter class. Dart allows us to place more than one class in a file but, before the file becomes unwieldly, its best practice to separate the classes into different files. This makes the code more readable. Create another file in the lib folder called clock_dial_painter.dart. Add the following code to it:

Here’s what we did. At the bottom of the file, we have created an enum called ClockText that choose one of either roman or arabic numbering. Then we created the class ClockDialPainter that inherits from CustomPainter as usual. We want the hour ticks to be 10.0 units long and 3.0 thick while the minute ticks will be 5.0 units long and 1.5 units thick. The ClockDialPainter constructor takes a named parameter clockText which is set to default to the enum value ClockText.roman if unspecified. Then we initialize the tickPaint, textPainter as well as the textStyle variables.

Now we start drawing. First we save our canvas position like we have done before, move the origin to the middle of the Container size, count to 60 and draw the tick marks using the appropriate length and thickness by checking if the position is supposed to be a minute or an hour mark. On each hour mark, we save the canvas position again, translate to -radius+20 units up, choose whether to draw the text using Arabic or Roman numerals, paints the text, then returns to the origin to the middle of the size again so the next tick mark can be painted. Then the canvas is rotated (line 78) and the next tick mark is drawn. On line 67, we keep the text vertical by first compensating for the amount of rotation the canvas has done through rotating the canvas back by the same amount before each text is drawn.

In the clock_face.dart file, import the clock_dial_painter.dart. This is what it gets us:

When clockText is ClockText.arabic
When clockText is ClockText.roman

Looking good.

We are almost done. Next we will be adding the clock hands and making them move so we get a function clock. Follow me

--

--