Created
June 28, 2020 15:24
-
-
Save dhruvilp/8031f26428bf5b5f017eb56036711600 to your computer and use it in GitHub Desktop.
Curved Texts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import 'dart:math' as math; | |
import 'package:flutter/material.dart'; | |
void main() => runApp(MyApp()); | |
class MyApp extends StatelessWidget { | |
@override | |
Widget build(BuildContext context) { | |
return MaterialApp( | |
title: 'Flutter Demo', | |
debugShowCheckedModeBanner: false, | |
theme: ThemeData( | |
primarySwatch: Colors.blue, | |
), | |
home: MyHomePage(title: 'Flutter Demo Home Page'), | |
); | |
} | |
} | |
class MyHomePage extends StatefulWidget { | |
MyHomePage({Key key, this.title}) : super(key: key); | |
final String title; | |
@override | |
_MyHomePageState createState() => _MyHomePageState(); | |
} | |
class _MyHomePageState extends State<MyHomePage> { | |
@override | |
Widget build(BuildContext context) { | |
return Scaffold( | |
appBar: AppBar( | |
title: Text(widget.title), | |
), | |
body: Stack( | |
children: [ | |
Center( | |
child: Container( | |
width: 210.0, | |
height: 210.0, | |
decoration: BoxDecoration( | |
borderRadius: BorderRadius.circular(120.0), | |
border: Border.all(color: Colors.black, width: 1.5), | |
), | |
), | |
), | |
Center( | |
child: Container( | |
width: 150.0, | |
height: 150.0, | |
decoration: BoxDecoration( | |
borderRadius: BorderRadius.circular(120.0), | |
border: Border.all(color: Colors.black, width: 1.5), | |
), | |
), | |
), | |
Center( | |
child: Padding( | |
padding: const EdgeInsets.only( | |
left: 86.0, | |
bottom: 74.0, | |
), | |
child: CustomPaint( | |
size: Size(45, 45), | |
painter: DrawTriangle(), | |
), | |
), | |
), | |
Center( | |
child: CurvedText( | |
text: '|--------------------------- HOST ID # HC1983012522', | |
radius: 80.0, | |
textStyle: Theme.of(context).textTheme.subtitle1.copyWith( | |
letterSpacing: 1.0, | |
), | |
), | |
), | |
], | |
), | |
); | |
} | |
} | |
class CurvedText extends StatelessWidget { | |
const CurvedText({ | |
Key key, | |
@required this.radius, | |
@required this.text, | |
@required this.textStyle, | |
this.startAngle = 0, | |
}) : super(key: key); | |
final double radius; | |
final String text; | |
final double startAngle; | |
final TextStyle textStyle; | |
@override | |
Widget build(BuildContext context) => CustomPaint( | |
painter: _Painter( | |
radius, | |
text, | |
textStyle, | |
initialAngle: startAngle, | |
), | |
); | |
} | |
class _Painter extends CustomPainter { | |
_Painter(this.radius, this.text, this.textStyle, {this.initialAngle = 0}); | |
final num radius; | |
final String text; | |
final double initialAngle; | |
final TextStyle textStyle; | |
final _textPainter = TextPainter(textDirection: TextDirection.ltr); | |
@override | |
void paint(Canvas canvas, Size size) { | |
canvas.translate(size.width / 2, size.height / 2 - radius); | |
if (initialAngle != 0) { | |
final d = 2 * radius * math.sin(initialAngle / 2); | |
final rotationAngle = _calculateRotationAngle(0, initialAngle); | |
canvas.rotate(rotationAngle); | |
canvas.translate(d, 0); | |
} | |
double angle = initialAngle; | |
for (int i = 0; i < text.length; i++) { | |
angle = _drawLetter(canvas, text[i], angle); | |
} | |
} | |
double _drawLetter(Canvas canvas, String letter, double prevAngle) { | |
_textPainter.text = TextSpan(text: letter, style: textStyle); | |
_textPainter.layout( | |
minWidth: 0, | |
maxWidth: double.maxFinite, | |
); | |
final double d = _textPainter.width; | |
final double alpha = 2 * math.asin(d / (2 * radius)); | |
final newAngle = _calculateRotationAngle(prevAngle, alpha); | |
canvas.rotate(newAngle); | |
_textPainter.paint(canvas, Offset(0, -_textPainter.height)); | |
canvas.translate(d, 0); | |
return alpha; | |
} | |
double _calculateRotationAngle(double prevAngle, double alpha) => | |
(alpha + prevAngle) / 2; | |
@override | |
bool shouldRepaint(CustomPainter oldDelegate) => true; | |
} | |
class DrawTriangle extends CustomPainter { | |
Paint _paint; | |
DrawTriangle() { | |
_paint = Paint() | |
..color = Colors.black | |
..style = PaintingStyle.fill; | |
} | |
@override | |
void paint(Canvas canvas, Size size) { | |
var path = Path(); | |
path.moveTo(-size.width / 2, 0); | |
path.lineTo(0, -size.height); | |
path.lineTo(-size.height, -size.width); | |
path.close(); | |
canvas.drawPath(path, _paint); | |
} | |
@override | |
bool shouldRepaint(CustomPainter oldDelegate) { | |
return false; | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment