Skip to content

Instantly share code, notes, and snippets.

@dhruvilp
Created June 28, 2020 15:24
Show Gist options
  • Save dhruvilp/8031f26428bf5b5f017eb56036711600 to your computer and use it in GitHub Desktop.
Save dhruvilp/8031f26428bf5b5f017eb56036711600 to your computer and use it in GitHub Desktop.
Curved Texts
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