When I was surfing in my spare time, I came across this design drawing and my eyes lit up. I felt this design and idea was very cool and decided to implement it. The author of the design drawing is not found, if anyone knows, please let me know, I will add the design reference, welcome to mineGithub
Source making
Video address
Solid and sound
Analysis and design, we are divided into two parts to achieve: 1 dial part 2 lower part of the switch. For the logic code omitted below, please go to Github for complete code
1. Dial part
1.1 Observe the style of the dial and divide the tasks that need to be done
- Gradient background, used as second hand
- Draw small white dots
- Draw a large yellow dot with a shadow to use as an hour hand
- Draw time text
- Turn on the timer and start the clock
A lot of the dial parts need to be drawn ourselves, so we can use CustomPaint to do all the drawing. CustomPaint provides the ability to customize widgets by exposing a canvas on which widgets can be drawn. What we’re doing here is drawing the dial as the background, which is the painter property, CustomPainter, Rewrite paint(Canvas Canvas,Size Size) and shouldRepaint(covariant CustomPainter oldDelegate) to do all of our drawing. Ok, let’s start happily.
1.2 Gradient background, used as second hand
As you can see from the picture, gradient is a scan gradient that fills the screen and is located in the top half of the screen. First we create the scan gradient object. This scan gradient creates a shader. Then we attach the shader to a brush and draw across the canvas. Note the calls to canvas.save() and canvas.restore() when the canvas is drawn. To get the second hand moving, start a Timer task that refreshes the view every second.
var circle = Rect.fromCircle(center: Offset(0, 0), radius: _screenHeight); Var sweepGradient = sweepGradient (colors: [_startColor, _endColor],); Paint _paintGradient = Paint().. isAntiAlias = true .. shader = sweepGradient.createShader(circle) .. style = PaintingStyle.fill; DateTime = datetime.now (); DateTime = datetime.now (); var hour = dateTime.hour; var minute = dateTime.minute; var second = dateTime.second; Canvas. Translate (_screenWidth / 2, _screenHeight / 100 * 35); // Draw the gradient background canvas.save(); Rotate(_getRotate(second)); rotate(_getRotate(second)); canvas.drawCircle(Offset(0, 0), _screenHeight, _paintGradient); canvas.restore();Copy the code
1.3 Draw small white dots
Here you need to draw 24 white dots, with an average of 360 degrees, by rotating the canvas to draw white dots at different angles.
for (double i = 0; i < _numPoint; i++) { canvas.save(); // double deg = 360 / _numPoint * i; canvas.rotate(deg / 180 * pi); _paintDial.color = Colors.white; DrawCircle (Offset(_radius, 0), 3, _paintDial); canvas.restore(); . canvas.restore(); }Copy the code
1.4 Draw a large yellow dot with a shadow as the hour hand
The large yellow dots are treated as clockwise, because the Angle of clockwise and canvas is not consistent, so it needs to be converted. In addition, we add shadows for the large dots.
for (double i = 0; i < _numPoint; i++) { canvas.save(); double deg = 360 / _numPoint * i; canvas.rotate(deg / 180 * pi); _paintDial.color = Colors.white; canvas.drawCircle(Offset(_radius, 0), 3, _paintDial); If (isShowBigCircle(hour, I)) {// Draw a shadow Path Path = Path().. addArc(Rect.fromCircle(center: Offset(_radius, 0), radius: 8), 0, pi * 2); canvas.drawShadow(path, Colors.yellow, 4, true); // Paint the dot _paintdia.color = color.yellow; canvas.drawCircle(Offset(_radius, 0), 8, _paintDial); } else { _paintDial.color = Colors.white; canvas.drawCircle(Offset(_radius, 0), 3, _paintDial); } canvas.restore(); . }Copy the code
1.5 Draw time text
The canvas draws text by calling canvas.drawParagraph(Paragraph Offset). A Paragraph object is created through ParagraphBuilder, and the font style can be set by ParagraphBuilder
// Set a text style _timeParagraphBuilder = ParagraphBuilder(ParagraphStyle(textAlign: textalign.center, fontSize: 70, maxLines: 1, fontWeight: FontWeight.bold)); DateTime = datetime.now (); DateTime = datetime.now (); var hour = dateTime.hour; var minute = dateTime.minute; var second = dateTime.second; // Draw the text canvas.save(); _timeParagraphBuilder.addText(_getTimeStr(hour, minute)); Paragraph paragraph = _timeParagraphBuilder.build(); paragraph.layout(ParagraphConstraints(width: 230)); canvas.drawParagraph(paragraph, Offset(-115,-42)); canvas.restore();Copy the code
2. Switch
Overall layout analysis, the switch part of the UI is at the bottom relative to the entire screen, using Stack and Align to achieve this layout style.
// Override Widget build(BuildContext context) {return Scaffold(body: Stack(children: [CustomPaint(Painter: DialPlate(context,Color.fromARGB(255, 70, 0, 144),Color.fromARGB(255, 121, 83, 254))), _getAlarms(), ], )); } // bottom view _getAlarms() {return Align(alignment: bottomLeft, child: Container(margin: EdgeInsets. Only (left: 16, right: 16), height: 200, width: double.infinity, child: Column( children: [ _getRow1(), _getRow2(), _getRow3(), ], ), ), ); } //_getRow1(), _getRow2(), _getRow3() similar to _getRow1() {return Container(alignment: alignment. CenterLeft, width: double.infinity, height: 50, child: Row( children: [ Text( '06:45', style: TextStyle( fontSize: 25, color: _firstSwitch == true ? _colorOn : _colorOff), ), Padding( padding: EdgeInsets.only(left: 18), child: Text( 'Wake up', style: TextStyle( fontSize: 18, color: _firstSwitch == true ? _colorOn : _colorOff), ), ), Expanded(child: SizedBox()), Container( width: 90, height: 10, child: Switch( value: _firstSwitch, onChanged: (onChanged) { setState(() {_firstSwitch = onChanged;}); }, activeColor: _switchActiveColor, activeTrackColor: Colors.black.withAlpha(100), inactiveThumbColor: _switchInActiveColor, inactiveTrackColor: Colors.black.withAlpha(20), ), ) ], ), ); }Copy the code