blob: 0666fd2e819fd34d176bc58e018487d36abcad08 [file] [log] [blame]
// Copyright 2014 The Flutter Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
import 'dart:math';
import 'dart:ui' as ui;
import 'package:flutter/material.dart';
import '../common.dart';
Map<String, WidgetBuilder> gradientPerfRoutes = <String, WidgetBuilder>{
kGradientPerfRecreateDynamicRouteName: (BuildContext _) => const RecreateDynamicPainterPage(),
kGradientPerfRecreateConsistentRouteName: (BuildContext _) => const RecreateConsistentPainterPage(),
kGradientPerfStaticConsistentRouteName: (BuildContext _) => const StaticConsistentPainterPage(),
};
typedef CustomPaintFactory = CustomPainter Function(double hue);
class GradientPerfHomePage extends StatelessWidget {
const GradientPerfHomePage({super.key});
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: const Text('Gradient Perf')),
body: ListView(
key: const Key(kGradientPerfScrollableName),
children: <Widget>[
ElevatedButton(
key: const Key(kGradientPerfRecreateDynamicRouteName),
child: const Text('Recreate Dynamic Gradients'),
onPressed: () {
Navigator.pushNamed(context, kGradientPerfRecreateDynamicRouteName);
},
),
ElevatedButton(
key: const Key(kGradientPerfRecreateConsistentRouteName),
child: const Text('Recreate Same Gradients'),
onPressed: () {
Navigator.pushNamed(context, kGradientPerfRecreateConsistentRouteName);
},
),
ElevatedButton(
key: const Key(kGradientPerfStaticConsistentRouteName),
child: const Text('Static Gradients'),
onPressed: () {
Navigator.pushNamed(context, kGradientPerfStaticConsistentRouteName);
},
),
],
),
);
}
}
class _PainterPage extends StatefulWidget {
const _PainterPage({super.key, required this.title, required this.factory});
final String title;
final CustomPaintFactory factory;
@override
State<_PainterPage> createState() => _PainterPageState();
}
class RecreateDynamicPainterPage extends _PainterPage {
const RecreateDynamicPainterPage({super.key})
: super(title: 'Recreate Dynamic Gradients', factory: makePainter);
static CustomPainter makePainter(double f) {
return RecreatedDynamicGradients(baseFactor: f);
}
}
class RecreateConsistentPainterPage extends _PainterPage {
const RecreateConsistentPainterPage({super.key})
: super(title: 'Recreate Same Gradients', factory: makePainter);
static CustomPainter makePainter(double f) {
return RecreatedConsistentGradients(baseFactor: f);
}
}
class StaticConsistentPainterPage extends _PainterPage {
const StaticConsistentPainterPage({super.key})
: super(title: 'Reuse Same Gradients', factory: makePainter);
static CustomPainter makePainter(double f) {
return StaticConsistentGradients(baseFactor: f);
}
}
class _PainterPageState extends State<_PainterPage> with SingleTickerProviderStateMixin {
late AnimationController _controller;
@override
void initState() {
super.initState();
_controller = AnimationController(vsync: this);
_controller.repeat(period: const Duration(seconds: 2));
}
@override
void dispose() {
_controller.dispose();
super.dispose();
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text(widget.title),
),
body: Center(
child: AnimatedBuilder(
animation: _controller,
builder: (BuildContext context, Widget? child) {
return CustomPaint(
size: const Size(paintW, paintH),
painter: widget.factory(_controller.value),
willChange: true,
);
},
),
),
);
}
}
Color color(double factor) {
int v = ((factor * 255 * 3) % (255 * 3)).round();
if (v < 0) {
v += 255 * 3;
}
int r = 0;
int g = 0;
int b = 0;
if (v < 255) {
r = 255 - v;
g = v;
} else {
v -= 255;
if (v < 255) {
g = 255 - v;
b = v;
} else {
v -= 255;
b = 255 - v;
r = v;
}
}
return Color.fromARGB(255, r, g, b);
}
Shader rotatingGradient(double factor, double x, double y, double h) {
final double s = sin(factor * 2 * pi) * h/8;
final double c = cos(factor * 2 * pi) * h/8;
final double cx = x;
final double cy = y + h/2;
final Offset p0 = Offset(cx + s, cy + c);
final Offset p1 = Offset(cx - s, cy - c);
return ui.Gradient.linear(p0, p1, <Color>[
color(factor),
color(factor + 0.5),
]);
}
const int nAcross = 12;
const int nDown = 16;
const double cellW = 20;
const double cellH = 20;
const double hGap = 5;
const double vGap = 5;
const double paintW = hGap + (cellW + hGap) * nAcross;
const double paintH = vGap + (cellH + vGap) * nDown;
double x(int i, int j) {
return hGap + i * (cellW + hGap);
}
double y(int i, int j) {
return vGap + j * (cellH + vGap);
}
Shader gradient(double baseFactor, int i, int j) {
final double lineFactor = baseFactor + 1/3 + 0.5 * (j + 1) / (nDown + 1);
final double cellFactor = lineFactor + 1/3 * (i + 1) / (nAcross + 1);
return rotatingGradient(cellFactor, x(i, j) + cellW / 2, y(i, j), cellH);
}
class RecreatedDynamicGradients extends CustomPainter {
RecreatedDynamicGradients({required this.baseFactor});
final double baseFactor;
@override
void paint(Canvas canvas, Size size) {
final Paint p = Paint();
p.color = color(baseFactor);
canvas.drawRect(Offset.zero & size, p);
for (int j = 0; j < nDown; j++) {
for (int i = 0; i < nAcross; i++) {
p.shader = gradient(baseFactor, i, j);
canvas.drawRect(Rect.fromLTWH(x(i, j), y(i, j), cellW, cellH), p);
}
}
}
@override
bool shouldRepaint(CustomPainter oldDelegate) => true;
}
class RecreatedConsistentGradients extends CustomPainter {
RecreatedConsistentGradients({required this.baseFactor});
final double baseFactor;
@override
void paint(Canvas canvas, Size size) {
final Paint p = Paint();
p.color = color(baseFactor);
canvas.drawRect(Offset.zero & size, p);
for (int j = 0; j < nDown; j++) {
for (int i = 0; i < nAcross; i++) {
p.shader = gradient(0, i, j);
canvas.drawRect(Rect.fromLTWH(x(i, j), y(i, j), cellW, cellH), p);
}
}
}
@override
bool shouldRepaint(CustomPainter oldDelegate) => true;
}
class StaticConsistentGradients extends CustomPainter {
StaticConsistentGradients({required this.baseFactor});
final double baseFactor;
static List<List<Shader>> gradients = <List<Shader>>[
for (int j = 0; j < nDown; j++)
<Shader>[
for (int i = 0; i < nAcross; i++)
gradient(0, i, j),
],
];
@override
void paint(Canvas canvas, Size size) {
final Paint p = Paint();
p.color = color(baseFactor);
canvas.drawRect(Offset.zero & size, p);
for (int j = 0; j < nDown; j++) {
for (int i = 0; i < nAcross; i++) {
p.shader = gradients[j][i];
canvas.drawRect(Rect.fromLTWH(x(i, j), y(i, j), cellW, cellH), p);
}
}
}
@override
bool shouldRepaint(CustomPainter oldDelegate) => true;
}