feat: Adding paint attribute to SpriteWidget and SpriteAnimationWidget (#3298)

Adds a `Paint` attribute to the `SpriteWidget` and
`SpriteAnimationWidget` for an improved API.

---------

Co-authored-by: Lukas Klingsbo <me@lukas.fyi>
This commit is contained in:
Erick
2024-09-12 09:19:54 -03:00
committed by GitHub
parent 0113aa3761
commit a5338d0c20
6 changed files with 76 additions and 5 deletions

View File

@ -0,0 +1,28 @@
import 'dart:ui';
final paintChoices = [
'none',
'transparent',
'red tinted',
'green tinted',
'blue tinted',
];
final paintList = [
null,
Paint()..color = const Color(0x22FFFFFF),
Paint()
..colorFilter = const ColorFilter.mode(
Color(0x88FF0000),
BlendMode.srcATop,
),
Paint()
..colorFilter = const ColorFilter.mode(
Color(0x8800FF00),
BlendMode.srcATop,
),
Paint()
..colorFilter = const ColorFilter.mode(
Color(0x880000FF),
BlendMode.srcATop,
),
];

View File

@ -1,4 +1,5 @@
import 'package:dashbook/dashbook.dart';
import 'package:examples/stories/widgets/paints.dart';
import 'package:flame/extensions.dart';
import 'package:flame/widgets.dart';
import 'package:flutter/widgets.dart';
@ -20,6 +21,13 @@ Widget spriteAnimationWidgetBuilder(DashbookContext ctx) {
anchor: Anchor.valueOf(
ctx.listProperty('anchor', 'center', anchorOptions),
),
paint: paintList[paintChoices.indexOf(
ctx.listProperty(
'paint',
'none',
paintChoices,
),
)],
),
);
}

View File

@ -1,6 +1,7 @@
import 'dart:math';
import 'package:dashbook/dashbook.dart';
import 'package:examples/stories/widgets/paints.dart';
import 'package:flame/widgets.dart';
import 'package:flutter/material.dart';
@ -17,6 +18,13 @@ Widget spriteWidgetBuilder(DashbookContext ctx) {
anchor: Anchor.valueOf(
ctx.listProperty('anchor', 'center', anchorOptions),
),
paint: paintList[paintChoices.indexOf(
ctx.listProperty(
'paint',
'none',
paintChoices,
),
)],
),
);
}

View File

@ -30,6 +30,10 @@ class SpriteAnimationWidget extends StatelessWidget {
/// A callback that is called when the animation completes.
final VoidCallback? onComplete;
/// A custom [Paint] to be used when rendering the sprite.
/// When omitted the default paint from the [Sprite] class will be used.
final Paint? paint;
const SpriteAnimationWidget({
required SpriteAnimation animation,
required SpriteAnimationTicker animationTicker,
@ -38,6 +42,7 @@ class SpriteAnimationWidget extends StatelessWidget {
this.errorBuilder,
this.loadingBuilder,
this.onComplete,
this.paint,
super.key,
}) : _animationFuture = animation,
_animationTicker = animationTicker;
@ -57,6 +62,7 @@ class SpriteAnimationWidget extends StatelessWidget {
this.errorBuilder,
this.loadingBuilder,
this.onComplete,
this.paint,
super.key,
}) : _animationFuture = SpriteAnimation.load(path, data, images: images),
_animationTicker = null;
@ -74,6 +80,7 @@ class SpriteAnimationWidget extends StatelessWidget {
animationTicker: ticker,
anchor: anchor,
playing: playing,
paint: paint,
);
},
errorBuilder: errorBuilder,
@ -97,11 +104,14 @@ class InternalSpriteAnimationWidget extends StatefulWidget {
/// Should the [animation] be playing or not
final bool playing;
final Paint? paint;
const InternalSpriteAnimationWidget({
required this.animation,
required this.animationTicker,
this.playing = true,
this.anchor = Anchor.topLeft,
this.paint,
super.key,
});
@ -193,6 +203,7 @@ class _InternalSpriteAnimationWidgetState
painter: SpritePainter(
widget.animationTicker.getSprite(),
widget.anchor,
widget.paint,
),
);
}

View File

@ -8,16 +8,18 @@ import 'package:flutter/widgets.dart';
class SpritePainter extends CustomPainter {
final Sprite _sprite;
final Anchor _anchor;
final Paint? _paint;
final double _angle;
SpritePainter(this._sprite, this._anchor, {double angle = 0})
SpritePainter(this._sprite, this._anchor, this._paint, {double angle = 0})
: _angle = angle;
@override
bool shouldRepaint(SpritePainter oldDelegate) {
return oldDelegate._sprite != _sprite ||
oldDelegate._anchor != _anchor ||
oldDelegate._angle != _angle;
oldDelegate._angle != _angle ||
oldDelegate._paint != _paint;
}
@override
@ -33,12 +35,16 @@ class SpritePainter extends CustomPainter {
canvas.translateVector(boxAnchorPosition..sub(spriteAnchorPosition));
if (_angle == 0) {
_sprite.render(canvas, size: paintSize);
_sprite.render(canvas, size: paintSize, overridePaint: _paint);
} else {
canvas.renderRotated(
_angle,
spriteAnchorPosition,
(canvas) => _sprite.render(canvas, size: paintSize),
(canvas) => _sprite.render(
canvas,
size: paintSize,
overridePaint: _paint,
),
);
}
}

View File

@ -25,6 +25,10 @@ class SpriteWidget extends StatelessWidget {
/// A builder function that is called while the loading is on the way
final WidgetBuilder? loadingBuilder;
/// A custom [Paint] to be used when rendering the sprite.
/// When omitted the default paint from the [Sprite] class will be used.
final Paint? paint;
final FutureOr<Sprite> _spriteFuture;
/// renders the [sprite] as a Widget.
@ -36,6 +40,7 @@ class SpriteWidget extends StatelessWidget {
this.angle = 0,
this.errorBuilder,
this.loadingBuilder,
this.paint,
super.key,
}) : _spriteFuture = sprite;
@ -54,6 +59,7 @@ class SpriteWidget extends StatelessWidget {
Vector2? srcSize,
this.errorBuilder,
this.loadingBuilder,
this.paint,
super.key,
}) : _spriteFuture = Sprite.load(
path,
@ -71,6 +77,7 @@ class SpriteWidget extends StatelessWidget {
sprite: sprite,
anchor: anchor,
angle: angle,
paint: paint,
);
},
errorBuilder: errorBuilder,
@ -91,17 +98,20 @@ class InternalSpriteWidget extends StatelessWidget {
/// The angle to rotate this [sprite], in rad. (default = 0)
final double angle;
final Paint? paint;
const InternalSpriteWidget({
required this.sprite,
this.anchor = Anchor.topLeft,
this.angle = 0,
this.paint,
super.key,
});
@override
Widget build(BuildContext context) {
return CustomPaint(
painter: SpritePainter(sprite, anchor, angle: angle),
painter: SpritePainter(sprite, anchor, paint, angle: angle),
size: sprite.srcSize.toSize(),
);
}