Skip to content

Commit 32c0a1e

Browse files
committed
[FTD #5] fixing gap between line in curved underline
1 parent 02c57de commit 32c0a1e

File tree

8 files changed

+50
-103
lines changed

8 files changed

+50
-103
lines changed

.vscode/launch.json

Lines changed: 0 additions & 46 deletions
This file was deleted.

analysis_options.yaml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,4 +4,5 @@ linter:
44
rules:
55
lines_longer_than_80_chars: false
66
public_member_api_docs: false
7+
omit_local_variable_types: false
78

example/lib/screens/examples/underline_example_screen.dart

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -39,9 +39,9 @@ class UnderlineExampleScreen extends StatelessWidget {
3939
const SizedBox(height: 32),
4040
Center(
4141
child: TextDecorator.underlined(
42-
style: UnderlineStyle.curved,
42+
style: UnderlineStyle.horizontal,
4343
text: const Text(
44-
'Franz jagt im komplett verwahrlosten Taxi quer durch Berlin',
44+
'Franz jagt im komplett verwahrlosten Taxiiii quer Franz jagt im kompletr Franz jagt im kompletr Franz jagt im jagt im kompletr Franz jagt im',
4545
style: TextStyle(fontSize: 16),
4646
),
4747
color: Colors.red,

lib/src/modules/box/painter/bubble_box_painter.dart

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,7 @@ class BubbleBoxPainter extends CustomPainter {
2929
this.tip = const BubbleBoxTip(),
3030
});
3131
final Text text;
32-
final double padding; //! TODO: fix text not being centered
32+
final double padding; // TODO(everyone): fix text not being centered
3333
final Color bubbleColor;
3434
final double borderRadius;
3535
final BubbleBoxTip tip;
@@ -55,7 +55,7 @@ class BubbleBoxPainter extends CustomPainter {
5555
final bubbleHeight = textHeight + padding * 2;
5656

5757
// Calculate tail size
58-
//! TODO: extract
58+
// TODO(everyone): extract
5959
final tailHeight = bubbleHeight * 0.25;
6060

6161
final path = Path()
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
import 'dart:ui' as ui;
2+
3+
mixin LineGap {
4+
double calculateGapBetweenLines({
5+
required int lineIndex,
6+
required ui.LineMetrics line,
7+
required double strokeWidth,
8+
}) {
9+
return line.height + (line.descent / 2) + strokeWidth;
10+
}
11+
}
Lines changed: 24 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
import 'dart:ui' as ui;
22
import 'package:flutter/material.dart';
33
import 'package:flutter_text_decorator/src/modules/underline/base/underline_painter.dart';
4+
import 'package:flutter_text_decorator/src/modules/underline/mixins/line_gap_mixin.dart';
45

56
/// A [CustomPainter] that draws a curved or wavy underline beneath text.
67
///
@@ -29,12 +30,12 @@ import 'package:flutter_text_decorator/src/modules/underline/base/underline_pain
2930
/// ),
3031
/// )
3132
/// ```
32-
class CurvedUnderlinePainter extends UnderlinePainter {
33+
class CurvedUnderlinePainter extends UnderlinePainter with LineGap {
3334
CurvedUnderlinePainter({
3435
required this.text,
3536
required super.color,
3637
required super.strokeWidth,
37-
this.curvyFactor = 0.7,
38+
this.curvyFactor = 3,
3839
super.textStyle,
3940
});
4041

@@ -43,58 +44,44 @@ class CurvedUnderlinePainter extends UnderlinePainter {
4344

4445
@override
4546
void paint(Canvas canvas, Size size) {
46-
final currentTextStyle = super.textStyle ?? const TextStyle();
47-
final textSpan = TextSpan(text: text, style: currentTextStyle);
4847
final textPainter = TextPainter(
49-
text: textSpan,
48+
text: TextSpan(text: text, style: textStyle ?? const TextStyle()),
5049
textDirection: ui.TextDirection.ltr,
5150
)..layout(maxWidth: size.width);
5251

53-
final Paint paint = Paint()
54-
..color = super.color
52+
final paint = Paint()
53+
..color = color
5554
..style = PaintingStyle.stroke
56-
..strokeWidth = super.strokeWidth;
55+
..strokeWidth = strokeWidth;
5756

58-
final List<ui.LineMetrics> lines = textPainter.computeLineMetrics();
57+
final lines = textPainter.computeLineMetrics();
5958

60-
final double waveHeightUnit = super.strokeWidth * 3.0;
59+
double yOffset = 0;
6160

62-
for (int lineIdx = 0; lineIdx < lines.length; lineIdx++) {
63-
final line = lines[lineIdx];
61+
for (final line in lines) {
62+
final double startX = line.left;
63+
final double xEnd = startX + line.width;
6464

65-
final double startX = line.left + horizontalOffset.left;
66-
final double xEnd = line.left + line.width - horizontalOffset.right;
67-
final double effectiveLineWidth = xEnd - startX;
65+
if (line.width <= 0) continue;
6866

69-
if (effectiveLineWidth <= 0) {
70-
continue;
71-
}
67+
yOffset += calculateGapBetweenLines(line: line, lineIndex: line.lineNumber, strokeWidth: strokeWidth);
7268

73-
final double lineGapY = _calculateGapBetweenLines(lineIdx, line, super.strokeWidth);
74-
final double yCp1 = lineGapY - waveHeightUnit * curvyFactor;
75-
final double yCp2 = lineGapY + waveHeightUnit * curvyFactor;
76-
final double yEnd = lineGapY;
77-
final double xCp1 = startX + effectiveLineWidth * (1 / 3);
78-
final double xCp2 = startX + effectiveLineWidth * (2 / 3);
69+
final double y1 = yOffset - strokeWidth * curvyFactor;
70+
final double y2 = yOffset + strokeWidth * curvyFactor;
71+
final double yEnd = yOffset;
72+
final double x1 = startX + xEnd * (1 / 3);
73+
final double x2 = startX + xEnd * (2 / 3);
74+
final double x3 = xEnd;
75+
final double y3 = yEnd;
7976

8077
final Path path = Path()
81-
..moveTo(startX, lineGapY)
82-
..cubicTo(xCp1, yCp1, xCp2, yCp2, xEnd, yEnd);
78+
..moveTo(startX, yOffset)
79+
..cubicTo(x1, y1, x2, y2, x3, y3);
8380

8481
canvas.drawPath(path, paint);
8582
}
8683
}
8784

88-
double _calculateGapBetweenLines(int lineIndex, ui.LineMetrics line, double currentStrokeWidth) {
89-
double desiredGap = 5;
90-
if (lineIndex == 0) {
91-
desiredGap = 1;
92-
}
93-
return line.baseline + line.descent + desiredGap + (currentStrokeWidth / 2.0);
94-
}
95-
9685
@override
97-
bool shouldRepaint(covariant CustomPainter oldDelegate) {
98-
return false;
99-
}
86+
bool shouldRepaint(covariant CustomPainter oldDelegate) => false;
10087
}

lib/src/modules/underline/painter/horizontal_underline_painter.dart

Lines changed: 6 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ import 'dart:ui' as ui;
33
import 'package:flutter/material.dart';
44
import 'package:flutter_text_decorator/src/modules/underline/base/underline_painter.dart';
55
import 'package:flutter_text_decorator/src/modules/underline/classes/horizontal_offset.dart';
6+
import 'package:flutter_text_decorator/src/modules/underline/mixins/line_gap_mixin.dart';
67

78
/// A [CustomPainter] that draws a straight horizontal underline beneath text.
89
///
@@ -28,9 +29,7 @@ import 'package:flutter_text_decorator/src/modules/underline/classes/horizontal_
2829
/// child: Text("Underlined Text"),
2930
/// )
3031
/// ```
31-
class HorizontalUnderlinePainter extends UnderlinePainter {
32-
final String text;
33-
32+
class HorizontalUnderlinePainter extends UnderlinePainter with LineGap {
3433
HorizontalUnderlinePainter({
3534
required this.text,
3635
required super.color,
@@ -39,6 +38,8 @@ class HorizontalUnderlinePainter extends UnderlinePainter {
3938
super.horizontalOffset,
4039
});
4140

41+
final String text;
42+
4243
@override
4344
@override
4445
void paint(Canvas canvas, Size size) {
@@ -61,20 +62,13 @@ class HorizontalUnderlinePainter extends UnderlinePainter {
6162
final double endX = line.left + line.width - horizontalOffset.right;
6263
final double underlineY = yOffset + line.ascent + line.descent + strokeWidth;
6364

64-
if (_isLineLengthPositive(startX, endX)) {
65+
if (startX < endX) {
6566
canvas.drawLine(Offset(startX, underlineY), Offset(endX, underlineY), paint);
6667
}
67-
68-
yOffset += _calculateGapBetweenLines(line.lineNumber, line);
68+
yOffset += calculateGapBetweenLines(line: line, lineIndex: line.lineNumber, strokeWidth: strokeWidth);
6969
}
7070
}
7171

72-
bool _isLineLengthPositive(double x, double y) => x < y;
73-
74-
double _calculateGapBetweenLines(int lineIndex, ui.LineMetrics line) {
75-
return line.height + (line.descent / 2) + strokeWidth;
76-
}
77-
7872
@override
7973
bool shouldRepaint(covariant CustomPainter oldDelegate) => false;
8074
}

test/src/modules/underline/painter/curved_underline_painer_test.dart

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -5,10 +5,10 @@ import 'package:flutter_text_decorator/src/modules/underline/painter/curved_unde
55
void main() {
66
group('CurvedUnderlinePainter Tests', () {
77
testWidgets('renders CustomPaint with CurvedUnderlinePainter for single line text', (WidgetTester tester) async {
8-
const String testText = 'Hello Curved Underline';
9-
const TextStyle testTextStyle = TextStyle(fontSize: 24, color: Colors.black);
10-
const Color underlineColor = Colors.blue;
11-
const double underlineStrokeWidth = 2.0;
8+
const testText = 'Hello Curved Underline';
9+
const testTextStyle = TextStyle(fontSize: 24, color: Colors.black);
10+
const underlineColor = Colors.blue;
11+
const underlineStrokeWidth = 2.0;
1212

1313
await tester.pumpWidget(
1414
MaterialApp(

0 commit comments

Comments
 (0)