Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix: display of square badge with small content size #111

Open
wants to merge 9 commits into
base: dev
Choose a base branch
from
24 changes: 17 additions & 7 deletions example/lib/alarm_app.dart
Original file line number Diff line number Diff line change
Expand Up @@ -17,18 +17,28 @@ class _AlarmAppState extends State<AlarmApp> {
@override
Widget build(BuildContext context) {
return badges.Badge(
badgeStyle: badges.BadgeStyle(padding: EdgeInsets.all(7)),
badgeStyle: badges.BadgeStyle(
padding: EdgeInsets.zero,
borderSide: BorderSide(color: Colors.white, width: 2),
shape: badges.BadgeShape.triangle,
badgeGradient: badges.BadgeGradient.linear(
colors: [
Colors.red,
Colors.orange,
],
begin: Alignment.topLeft,
end: Alignment.bottomRight,
),
),
badgeAnimation: badges.BadgeAnimation.fade(
animationDuration: Duration(seconds: 1),
loopAnimation: _isLooped,
),
// onTap: () {
// setState(() => _isLooped = !_isLooped);
// },
ignorePointer: false,
// toAnimate: false,
badgeContent:
Text(counter.toString(), style: TextStyle(color: Colors.white)),
badgeContent: Text(
'!',
style: TextStyle(color: Colors.white),
),
position: badges.BadgePosition.topEnd(top: -12),
child: GestureDetector(
onTap: () {
Expand Down
67 changes: 61 additions & 6 deletions lib/src/badge.dart
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import 'package:badges/src/badge_border_gradient.dart';
import 'package:badges/src/utils/calculation_utils.dart';
import 'package:badges/src/utils/drawing_utils.dart';
import 'package:flutter/material.dart';
import 'package:flutter/scheduler.dart';

class Badge extends StatefulWidget {
const Badge({
Expand Down Expand Up @@ -62,10 +63,15 @@ class BadgeState extends State<Badge> with TickerProviderStateMixin {
late AnimationController _appearanceController;
late Animation<double> _animation;
bool enableLoopAnimation = false;
double? textSize;
final GlobalKey _key = GlobalKey();
double? _widgetSize;

@override
void initState() {
super.initState();
SchedulerBinding.instance
.addPostFrameCallback((_) => scaleWidgetSize(_key, badge: widget));
enableLoopAnimation =
widget.badgeAnimation.animationDuration.inMilliseconds > 0;
_animationController = AnimationController(
Expand Down Expand Up @@ -97,6 +103,30 @@ class BadgeState extends State<Badge> with TickerProviderStateMixin {
}
}

void scaleWidgetSize(GlobalKey key, {required Badge badge, Badge? oldBadge}) {
double newSize = 0;

if (badge.badgeContent is Text) {
final newText = badge.badgeContent as Text;
final size =
CalculationUtils.calculateSizeOfText(newText.data!, newText.style);
newSize = size.width >= size.height
? size.width * 1.1764
: size.height * 1.1764;
} else if (badge.badgeContent is Icon) {
newSize = (badge.badgeContent as Icon).size ?? 0;
} else {
final RenderBox? childBox =
_key.currentContext?.findRenderObject() as RenderBox?;
if (childBox != null) {
Size size = childBox.size;
newSize = size.height >= size.width ? size.height : size.width;
}
}
newSize *= badge.badgeStyle.shape == BadgeShape.triangle ? 1.7 : 1;
setState(() => _widgetSize = newSize);
}

@override
Widget build(BuildContext context) {
if (widget.child == null) {
Expand All @@ -113,7 +143,8 @@ class BadgeState extends State<Badge> with TickerProviderStateMixin {
widget.onTap == null
? widget.child!
: Padding(
padding: CalculationUtils.calculatePadding(widget.position),
padding: CalculationUtils.calculatePaddingByPosition(
widget.position),
child: widget.child!,
),
BadgePositioned(
Expand Down Expand Up @@ -157,7 +188,9 @@ class BadgeState extends State<Badge> with TickerProviderStateMixin {
borderRadius: widget.badgeStyle.borderRadius,
);
final isCustomShape = widget.badgeStyle.shape == BadgeShape.twitter ||
widget.badgeStyle.shape == BadgeShape.instagram;
widget.badgeStyle.shape == BadgeShape.instagram ||
widget.badgeStyle.shape == BadgeShape.triangle;
final isSquareShape = widget.badgeStyle.shape == BadgeShape.square;

final gradientBorder = widget.badgeStyle.borderGradient != null
? BadgeBorderGradient(
Expand All @@ -183,8 +216,18 @@ class BadgeState extends State<Badge> with TickerProviderStateMixin {
borderSide: widget.badgeStyle.borderSide,
),
child: Padding(
padding: widget.badgeStyle.padding,
child: widget.badgeContent,
padding: CalculationUtils.calculateBadgeContentPadding(
widget.badgeContent,
widget.badgeStyle,
),
child: SizedBox(
width: _widgetSize,
height: _widgetSize,
child: Center(
key: _key,
child: widget.badgeContent,
),
),
),
)
: Material(
Expand Down Expand Up @@ -214,8 +257,18 @@ class BadgeState extends State<Badge> with TickerProviderStateMixin {
border: gradientBorder,
),
child: Padding(
padding: widget.badgeStyle.padding,
child: widget.badgeContent,
padding: CalculationUtils.calculateBadgeContentPadding(
widget.badgeContent,
widget.badgeStyle,
),
child: SizedBox(
width: _widgetSize,
height: isSquareShape ? null : _widgetSize,
child: Center(
key: _key,
child: widget.badgeContent,
),
),
),
),
),
Expand Down Expand Up @@ -261,6 +314,8 @@ class BadgeState extends State<Badge> with TickerProviderStateMixin {
@override
void didUpdateWidget(Badge oldWidget) {
super.didUpdateWidget(oldWidget);
SchedulerBinding.instance.addPostFrameCallback(
(_) => scaleWidgetSize(_key, badge: widget, oldBadge: oldWidget));
if (widget.badgeAnimation.toAnimate) {
if (widget.badgeStyle.badgeColor != oldWidget.badgeStyle.badgeColor &&
widget.showBadge) {
Expand Down
5 changes: 5 additions & 0 deletions lib/src/badge_shape.dart
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import 'package:badges/badges.dart' as badges;
import 'package:badges/src/painters/triangle_badge_shape_painter.dart';
import 'package:flutter/material.dart';

/// Set of shapes that you can use for your [badges.Badge] widget.
Expand All @@ -15,6 +16,10 @@ enum BadgeShape {
/// * [RoundedRectangleBorder]
square,

/// To make the triangle badge .
/// See [TriangleBadgeShapePainter] for more details.
triangle,

/// To make the twitter badge .
/// See [TwitterBadgeShapePainter] for more details.
twitter,
Expand Down
4 changes: 2 additions & 2 deletions lib/src/badge_style.dart
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ class BadgeStyle {

/// Specifies padding for [badgeContent].
/// The default value is EdgeInsets.all(5.0).
final EdgeInsetsGeometry padding;
final EdgeInsetsGeometry? padding;

const BadgeStyle({
this.shape = BadgeShape.circle,
Expand All @@ -41,6 +41,6 @@ class BadgeStyle {
this.elevation = 2,
this.badgeGradient,
this.borderGradient,
this.padding = const EdgeInsets.all(5.0),
this.padding,
});
}
64 changes: 35 additions & 29 deletions lib/src/painters/instagram_badge_shape_painter.dart
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
import 'dart:math' as math;

import 'package:badges/badges.dart';
import 'package:badges/src/utils/gradient_utils.dart';
import 'package:flutter/material.dart';
Expand All @@ -21,15 +23,19 @@ class InstagramBadgeShapePainter extends CustomPainter {
final width = size.width;
final height = size.height;

final double maxSize = math.max(width, height);

canvas.clipRect(Offset.zero & Size(maxSize, maxSize));

Path path = Path();
Paint paint = Paint();
Paint paintBorder = Paint();

if (badgeGradient != null) {
paint.shader = GradientUtils.getGradientShader(
badgeGradient: badgeGradient!,
width: width,
height: height,
width: maxSize,
height: maxSize,
);
}
paintBorder
Expand All @@ -41,36 +47,36 @@ class InstagramBadgeShapePainter extends CustomPainter {
if (borderGradient != null) {
paintBorder.shader = GradientUtils.getGradientShader(
badgeGradient: borderGradient!,
width: width,
height: height,
width: maxSize,
height: maxSize,
);
}

path.moveTo(width * 0.14, height * 0.14);
path.lineTo(width * 0.3, height * 0.14);
path.lineTo(width * 0.385, 0);
path.lineTo(width * 0.515, height * 0.08);
path.lineTo(width * 0.627, height * 0.012);
path.lineTo(width * 0.7, height * 0.134);
path.lineTo(width * 0.867, height * 0.134);
path.lineTo(width * 0.867, height * 0.3);
path.lineTo(width, height * 0.38);
path.lineTo(width * 0.922, height * 0.505);
path.lineTo(width * 0.995, height * 0.629);
path.lineTo(width * 0.866, height * 0.706);
path.lineTo(width * 0.866, height * 0.868);
path.lineTo(width * 0.697, height * 0.868);
path.lineTo(width * 0.618, height * 0.996);
path.lineTo(width * 0.5, height * 0.924);
path.lineTo(width * 0.379, height * 0.996);
path.lineTo(width * 0.302, height * 0.868);
path.lineTo(width * 0.14, height * 0.868);
path.lineTo(width * 0.14, height * 0.702);
path.lineTo(width * 0.004, height * 0.618);
path.lineTo(width * 0.08, height * 0.494);
path.lineTo(width * 0.012, height * 0.379);
path.lineTo(width * 0.14, height * 0.306);
path.lineTo(width * 0.14, height * 0.14);
path.moveTo(maxSize * 0.14, maxSize * 0.14);
path.lineTo(maxSize * 0.3, maxSize * 0.14);
path.lineTo(maxSize * 0.385, 0);
path.lineTo(maxSize * 0.515, maxSize * 0.08);
path.lineTo(maxSize * 0.627, maxSize * 0.012);
path.lineTo(maxSize * 0.7, maxSize * 0.134);
path.lineTo(maxSize * 0.867, maxSize * 0.134);
path.lineTo(maxSize * 0.867, maxSize * 0.3);
path.lineTo(maxSize, maxSize * 0.38);
path.lineTo(maxSize * 0.922, maxSize * 0.505);
path.lineTo(maxSize * 0.995, maxSize * 0.629);
path.lineTo(maxSize * 0.866, maxSize * 0.706);
path.lineTo(maxSize * 0.866, maxSize * 0.868);
path.lineTo(maxSize * 0.697, maxSize * 0.868);
path.lineTo(maxSize * 0.618, maxSize * 0.996);
path.lineTo(maxSize * 0.5, maxSize * 0.924);
path.lineTo(maxSize * 0.379, maxSize * 0.996);
path.lineTo(maxSize * 0.302, maxSize * 0.868);
path.lineTo(maxSize * 0.14, maxSize * 0.868);
path.lineTo(maxSize * 0.14, maxSize * 0.702);
path.lineTo(maxSize * 0.004, maxSize * 0.618);
path.lineTo(maxSize * 0.08, maxSize * 0.494);
path.lineTo(maxSize * 0.012, maxSize * 0.379);
path.lineTo(maxSize * 0.14, maxSize * 0.306);
path.lineTo(maxSize * 0.14, maxSize * 0.14);

paint.color = color!;
canvas.drawPath(path, paint);
Expand Down
78 changes: 78 additions & 0 deletions lib/src/painters/triangle_badge_shape_painter.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
import 'dart:math' as math;

import 'package:badges/badges.dart';
import 'package:badges/src/utils/gradient_utils.dart';
import 'package:flutter/material.dart';

class TriangleBadgeShapePainter extends CustomPainter {
Color? color;
BadgeGradient? badgeGradient;
BadgeGradient? borderGradient;
BorderSide? borderSide;

TriangleBadgeShapePainter({
Key? key,
this.color = Colors.blue,
this.badgeGradient,
this.borderGradient,
this.borderSide,
});

@override
void paint(Canvas canvas, Size size) {
final width = size.width;
final height = size.height;

final double maxSize = math.max(width, height);

canvas.clipRect(Offset.zero & Size(maxSize, maxSize));

Path path = Path();
Paint paint = Paint();
Paint paintBorder = Paint();

if (badgeGradient != null) {
paint.shader = GradientUtils.getGradientShader(
badgeGradient: badgeGradient!,
width: maxSize,
height: maxSize,
);
}
paintBorder
..color = borderSide?.color ?? Colors.white
..style = PaintingStyle.stroke
..strokeCap = StrokeCap.round
..strokeWidth = borderSide?.width ?? 0;

if (borderGradient != null) {
paintBorder.shader = GradientUtils.getGradientShader(
badgeGradient: borderGradient!,
width: maxSize,
height: maxSize,
);
}
path
..moveTo(maxSize * 0.132, maxSize * 0.888)
..arcToPoint(Offset(maxSize * 0.075, maxSize * 0.772),
radius: Radius.circular(maxSize * 0.09))
..lineTo(maxSize * 0.428, maxSize * 0.156)
..arcToPoint(Offset(maxSize * 0.582, maxSize * 0.156),
radius: Radius.circular(maxSize * 0.09))
..lineTo(maxSize * 0.928, maxSize * 0.756)
..arcToPoint(Offset(maxSize * 0.868, maxSize * 0.888),
radius: Radius.circular(maxSize * 0.09))
..lineTo(maxSize * 0.132, maxSize * 0.888);
path.close();

paint.color = color!;
canvas.drawPath(path, paint);
if (borderSide != BorderSide.none) {
canvas.drawPath(path, paintBorder);
}
}

@override
bool shouldRepaint(covariant CustomPainter oldDelegate) {
return true;
}
}
Loading