-
Notifications
You must be signed in to change notification settings - Fork 29.7k
Description
drawImageNine is not well documented for the case where the center region disappears, but it is implemented consistently for all of the Skia backed platforms such as mobile and the canvaskit web renderer. Unfortunately, the html web renderer throws exceptions on a debug build and produces an inconsistent output on non-debug builds.
There are already issues filed for the lack of documentation of drawImageNine and the centerSlice properties, but the behavior that Skia provides when the center region disappears makes sense and should become the documented behavior. Basically, the center slice takes up all of the scaling until it goes to a zero size. It is fine to have an empty center section, not a condition that should be asserted as in the web renderer. At that point only the 4 corners of the image are visible and if you continue to scale down then the corners will start scaling down with the reduced size.
Here is the test sample:
Code sample:
import 'dart:ui' as ui;
import 'package:flutter/material.dart';
void main() {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Nine Slice Demo',
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: MyHomePage(title: 'Nine Slice Demo'),
);
}
}
class MyHomePage extends StatefulWidget {
MyHomePage({Key key, this.title}) : super(key: key);
final String title;
@override
_MyHomePageState createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
ui.Image theImage;
double size = 200.0;
@override
void initState() {
super.initState();
makeImage().then((image) => setState(() {
theImage = image;
}));
}
void newSize(double newSize) {
setState(() {
size = newSize;
});
}
Future<ui.Image> makeImage() {
Rect bounds = Rect.fromLTWH(0, 0, 200, 200);
ui.PictureRecorder recorder = ui.PictureRecorder();
Canvas canvas = Canvas(recorder, bounds);
paintCheckerboard(canvas, bounds, 10, 10, Colors.white, Colors.grey);
paintCheckerboard(canvas, bounds.deflate(50), 10, 10, Colors.blue, Colors.green);
return recorder.endRecording().toImage(200, 200);
}
paintCheckerboard(Canvas canvas, Rect bounds, double w, double h, Color c1, Color c2) {
Paint p = Paint();
double y = bounds.top;
for (int i = 0; i < bounds.height / h; i++) {
double x = bounds.left;
for (int j = 0; j < bounds.width / w; j++) {
p.color = (i ^ j) & 1 == 0 ? c1 : c2;
canvas.drawRect(Rect.fromLTWH(x, y, w, h), p);
x += w;
}
y += h;
}
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text(widget.title),
),
body: Center(
child: theImage == null ? null : CustomPaint(
size: Size(size, size),
painter: NineSlicePainter(
theImage,
const Rect.fromLTWH(50, 50, 100, 100),
Rect.fromLTWH(0, 0, size, size),
),
willChange: false,
isComplex: false,
),
),
bottomNavigationBar: BottomAppBar(
child: Wrap(
children: [
Slider(
value: size,
min: 50,
max: 300,
onChanged: theImage == null ? null : newSize,
),
],
),
),
);
}
}
class NineSlicePainter extends CustomPainter {
NineSlicePainter(this.theImage, this.center, this.dst);
Rect center;
Rect dst;
ui.Image theImage;
@override
void paint(Canvas canvas, Size size) {
canvas.drawImageNine(theImage, center, dst, Paint());
}
@override
bool shouldRepaint(CustomPainter oldDelegate) {
if (oldDelegate is NineSlicePainter) {
return oldDelegate.dst != dst || oldDelegate.theImage != theImage;
}
return true;
}
}