Add TextBoxConfig options and fix TextBoxComponent bugs (#534)

* Add TextBoxConfig options and fix TextBxoComponent bugs

* Add changelog entry

* Fix snackbar deprecation

* All examples to have publish to none

* One argument per line

* No explicit types for local variables

* Cache the width

* Fix formatting
This commit is contained in:
Lukas Klingsbo
2020-11-22 21:45:10 +01:00
committed by renancaraujo
parent 5dc93e1987
commit d09d2bd449
30 changed files with 140 additions and 61 deletions

View File

@ -1,6 +1,8 @@
# CHANGELOG
## [next]
- Fix TextBoxComponent rendering
- Add TextBoxConfig options; margins and growingBox
## 1.0.0-rc2
- Improve IsometricTileMap and Spritesheet classes

View File

@ -60,14 +60,6 @@ class _MyHomePageState extends State<MyHomePage> {
setState(() => _position += Vector2.all(10));
}
void _clickFab(GlobalKey<ScaffoldState> key) {
key.currentState.showSnackBar(
const SnackBar(
content: const Text('You clicked the FAB!'),
),
);
}
@override
Widget build(BuildContext context) {
final key = GlobalKey<ScaffoldState>();
@ -102,7 +94,11 @@ class _MyHomePageState extends State<MyHomePage> {
),
),
floatingActionButton: FloatingActionButton(
onPressed: () => _clickFab(key),
onPressed: () => ScaffoldMessenger.of(context).showSnackBar(
const SnackBar(
content: const Text('You clicked the FAB!'),
),
),
child: const Icon(Icons.add),
),
);

View File

@ -1,6 +1,8 @@
name: animation_widget
description: A sample Flame project to showcase the SpriteAnimationWidget widget.
publish_to: 'none'
version: 0.1.0
environment:

View File

@ -1,6 +1,8 @@
name: animations
description: Flame sample game showcasing animations features
publish_to: 'none'
version: 1.0.0+1
environment:

View File

@ -1,6 +1,8 @@
name: aseprite
description: Flame sample for using Aseprite animations
publish_to: 'none'
version: 1.0.0+1
environment:

View File

@ -1,6 +1,8 @@
name: debug
description: Flame sample for using debug features
publish_to: 'none'
version: 1.0.0+1
environment:

View File

@ -1,6 +1,8 @@
name: combined_effects
description: Flame sample game showcasing combined effects
publish_to: 'none'
version: 1.0.0+1
environment:

View File

@ -1,6 +1,8 @@
name: infinite_effects
description: Flame sample game showcasing infinite effects
publish_to: 'none'
version: 1.0.0+1
environment:

View File

@ -1,6 +1,8 @@
name: sequence_effect
description: Flame sample game showcasing the sequence effect
publish_to: 'none'
version: 1.0.0+1
environment:

View File

@ -1,6 +1,8 @@
name: effects
description: A Flame game showcasing the use of the effects api
publish_to: 'none'
version: 1.0.0+1
environment:

View File

@ -1,6 +1,8 @@
name: gestures
description: A flame game showcasing the use of gestures callbacks
publish_to: 'none'
version: 1.0.0+1
environment:

View File

@ -1,6 +1,8 @@
name: go_desktop
description: Flame sample game on using the go flutter desktop framework
publish_to: 'none'
version: 1.0.0+1
environment:

View File

@ -1,6 +1,8 @@
name: isometric
description: Example of isometric tilemap using Flame
publish_to: 'none'
version: 0.1.0
environment:

View File

@ -1,6 +1,8 @@
name: joystick
description: A flame game showcasing the use of joystick
publish_to: 'none'
version: 1.0.0+1
environment:

View File

@ -1,6 +1,8 @@
name: keyboard
description: Simple Flame project showcasing how to use the Keyboard events
publish_to: 'none'
version: 1.0.0+1
environment:

View File

@ -1,6 +1,8 @@
name: nine_tile_box
description: Flame sample for using the nine_tile_box feature
publish_to: 'none'
version: 1.0.0+1
environment:

View File

@ -1,6 +1,8 @@
name: parallax
description: Flame sample game showcasing the parallax features
publish_to: 'none'
version: 1.0.0+1
environment:

View File

@ -1,6 +1,8 @@
name: particles
description: Flame sample game showcasing particle effects
publish_to: 'none'
version: 1.0.0
environment:

View File

@ -1,6 +1,8 @@
name: render_flip
description: Flame sample game showcasing animations features
publish_to: 'none'
version: 1.0.0+1
environment:

View File

@ -1,6 +1,8 @@
name: sprite_batch
description: Showcasing SpriteBatch features
publish_to: 'none'
version: 1.0.0+1
environment:

View File

@ -1,6 +1,8 @@
name: sprites
description: Flame sample game showcasing rendering 500 sprites
publish_to: 'none'
version: 1.0.0+1
environment:

View File

@ -1,6 +1,8 @@
name: spritesheet
description: Flame sample game showcasing spritesheet features
publish_to: 'none'
version: 1.0.0+1
environment:

View File

@ -20,16 +20,31 @@ TextConfig tiny = regular.withFontSize(12.0);
class MyTextBox extends TextBoxComponent {
MyTextBox(String text)
: super(text, config: tiny, boxConfig: TextBoxConfig(timePerChar: 0.05));
: super(
text,
config: tiny,
boxConfig: TextBoxConfig(
timePerChar: 0.05,
growingBox: true,
margins: const EdgeInsets.symmetric(horizontal: 10, vertical: 15),
),
);
@override
void drawBackground(Canvas c) {
final Rect rect = Rect.fromLTWH(0, 0, width, height);
c.drawRect(rect, Paint()..color = const Color(0xFFFF00FF));
final margin = boxConfig.margins;
final Rect innerRect = Rect.fromLTWH(
margin.left,
margin.top,
width - margin.horizontal,
height - margin.vertical,
);
c.drawRect(
rect.deflate(boxConfig.margin),
innerRect,
Paint()
..color = BasicPalette.black.color
..color = BasicPalette.white.color
..style = PaintingStyle.stroke);
}
}

View File

@ -1,6 +1,8 @@
name: text
description: A sample Flame project that renders texts.
publish_to: 'none'
version: 0.1.0
environment:

View File

@ -1,6 +1,8 @@
name: timer
description: Example app using Timer class
publish_to: 'none'
version: 1.0.0+1
environment:

View File

@ -1,6 +1,8 @@
name: widgets
description: A Flutter project showcasing Flame's widgets.
publish_to: 'none'
version: 1.0.0+1
environment:

View File

@ -1,6 +1,8 @@
name: with_widgets_overlay
description: A Flame game showcasing how to use the WithWidgetsOverlay feature
publish_to: 'none'
version: 1.0.0+1
environment:

View File

@ -64,6 +64,10 @@ class MyGame extends BaseGame {
`TextBoxComponent` is very similar to `TextComponent`, but as its name suggest it is used to render text inside a bounding box, creating line breaks according to the provided box size.
You can decide if the box should grow as the text is written or if it should be static by the `growingBox` variable in the `TextBoxConfig`.
If you want to change the margins of the box use the `margins` variable in the `TextBoxConfig`.
Example usage:
```dart
@ -83,4 +87,4 @@ class MyTextBox extends TextBoxComponent {
}
```
Both components are showcased in a working example [here](https://github.com/luanpotter/flame/tree/master/doc/examples/text)
Both components are showcased in an example [here](https://github.com/luanpotter/flame/tree/master/doc/examples/text)

View File

@ -1,6 +1,8 @@
name: position_component
description: A new Flutter project.
publish_to: 'none'
version: 0.1.0
environment:

View File

@ -2,25 +2,27 @@ import 'dart:async';
import 'dart:math' as math;
import 'dart:ui';
import 'package:flutter/widgets.dart' as widgets;
import 'package:flutter/widgets.dart' hide Image;
import '../extensions/vector2.dart';
import '../palette.dart';
import '../text_config.dart';
import '../extensions/vector2.dart';
import 'mixins/resizable.dart';
import 'position_component.dart';
class TextBoxConfig {
final double maxWidth;
final double margin;
final EdgeInsets margins;
final double timePerChar;
final double dismissDelay;
final bool growingBox;
TextBoxConfig({
this.maxWidth = 200.0,
this.margin = 8.0,
this.margins = const EdgeInsets.all(8.0),
this.timePerChar = 0.0,
this.dismissDelay = 0.0,
this.growingBox = false,
});
}
@ -28,8 +30,6 @@ class TextBoxComponent extends PositionComponent with Resizable {
static final Paint _imagePaint = BasicPalette.white.paint
..filterQuality = FilterQuality.high;
Vector2 p = Vector2.zero();
String _text;
TextConfig _config;
TextBoxConfig _boxConfig;
@ -37,9 +37,11 @@ class TextBoxComponent extends PositionComponent with Resizable {
List<String> _lines;
double _maxLineWidth = 0.0;
double _lineHeight;
int _totalLines;
double _lifeTime = 0.0;
Image _cache;
int _previousChar;
String get text => _text;
@ -57,24 +59,23 @@ class TextBoxComponent extends PositionComponent with Resizable {
_text = text;
_lines = [];
text.split(' ').forEach((word) {
final String possibleLine =
_lines.isEmpty ? word : _lines.last + ' ' + word;
final widgets.TextPainter p = config.toTextPainter(possibleLine);
_lineHeight ??= p.height;
if (p.width <= _boxConfig.maxWidth - 2 * _boxConfig.margin) {
final possibleLine = _lines.isEmpty ? word : _lines.last + ' ' + word;
final painter = config.toTextPainter(possibleLine);
_lineHeight ??= painter.height;
if (painter.width <=
_boxConfig.maxWidth - _boxConfig.margins.horizontal) {
if (_lines.isNotEmpty) {
_lines.last = possibleLine;
} else {
_lines.add(possibleLine);
}
_updateMaxWidth(p.width);
_updateMaxWidth(painter.width);
} else {
_lines.add(word);
_updateMaxWidth(config.toTextPainter(word).width);
}
});
redrawLater();
_totalLines = _lines.length;
}
void _updateMaxWidth(double w) {
@ -103,39 +104,49 @@ class TextBoxComponent extends PositionComponent with Resizable {
return _lines.length - 1;
}
double _withMargins(double size) => size + 2 * _boxConfig.margin;
@override
double get width => currentWidth;
@override
double get height => currentHeight;
double get totalWidth => _withMargins(_maxLineWidth);
double get totalHeight => _withMargins(_lineHeight * _lines.length);
Vector2 get size => Vector2(width, height);
double getLineWidth(String line, int charCount) {
return _withMargins(_config
return _config
.toTextPainter(line.substring(0, math.min(charCount, line.length)))
.width);
.width;
}
double get currentWidth {
double _cachedWidth;
@override
double get width {
if (_cachedWidth != null) {
return _cachedWidth;
}
if (_boxConfig.growingBox) {
int i = 0;
int totalCharCount = 0;
final int _currentChar = currentChar;
final int _currentLine = currentLine;
return _lines.sublist(0, _currentLine + 1).map((line) {
final double textWidth = _lines.sublist(0, _currentLine + 1).map((line) {
final int charCount =
(i < _currentLine) ? line.length : (_currentChar - totalCharCount);
totalCharCount += line.length;
i++;
return getLineWidth(line, charCount);
}).reduce(math.max);
_cachedWidth = textWidth + _boxConfig.margins.horizontal;
} else {
_cachedWidth = _boxConfig.maxWidth + _boxConfig.margins.horizontal;
}
return _cachedWidth;
}
double get currentHeight => _withMargins((currentLine + 1) * _lineHeight);
@override
double get height {
if (_boxConfig.growingBox) {
return _lineHeight * _lines.length + _boxConfig.margins.vertical;
} else {
return _lineHeight * _totalLines + _boxConfig.margins.vertical;
}
}
@override
void render(Canvas c) {
@ -160,19 +171,19 @@ class TextBoxComponent extends PositionComponent with Resizable {
final int _currentLine = currentLine;
int charCount = 0;
double dy = _boxConfig.margin;
double dy = _boxConfig.margins.top;
for (int line = 0; line < _currentLine; line++) {
charCount += _lines[line].length;
_config
.toTextPainter(_lines[line])
.paint(c, Offset(_boxConfig.margin, dy));
_drawLine(c, _lines[line], dy);
dy += _lineHeight;
}
final int max =
math.min(currentChar - charCount, _lines[_currentLine].length);
_config
.toTextPainter(_lines[_currentLine].substring(0, max))
.paint(c, Offset(_boxConfig.margin, dy));
_drawLine(c, _lines[_currentLine].substring(0, max), dy);
}
void _drawLine(Canvas c, String line, double dy) {
_config.toTextPainter(line).paint(c, Offset(_boxConfig.margins.left, dy));
}
void redrawLater() async {
@ -182,10 +193,11 @@ class TextBoxComponent extends PositionComponent with Resizable {
@override
void update(double dt) {
super.update(dt);
final int prevCurrentChar = currentChar;
_lifeTime += dt;
if (prevCurrentChar != currentChar) {
if (_previousChar != currentChar) {
_cachedWidth = null;
redrawLater();
}
_previousChar = currentChar;
}
}