Auto-format Framework (#160545)

This auto-formats all *.dart files in the repository outside of the
`engine` subdirectory and enforces that these files stay formatted with
a presubmit check.

**Reviewers:** Please carefully review all the commits except for the
one titled "formatted". The "formatted" commit was auto-generated by
running `dev/tools/format.sh -a -f`. The other commits were hand-crafted
to prepare the repo for the formatting change. I recommend reviewing the
commits one-by-one via the "Commits" tab and avoiding Github's "Files
changed" tab as it will likely slow down your browser because of the
size of this PR.

---------

Co-authored-by: Kate Lovett <katelovett@google.com>
Co-authored-by: LongCatIsLooong <31859944+LongCatIsLooong@users.noreply.github.com>
This commit is contained in:
Michael Goderbauer 2024-12-19 12:06:21 -08:00 committed by GitHub
parent 8e0993eda8
commit 5491c8c146
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
4411 changed files with 455108 additions and 415991 deletions

View File

@ -393,6 +393,7 @@ targets:
- name: Linux packages_autoroller - name: Linux packages_autoroller
presubmit: false presubmit: false
recipe: pub_autoroller/pub_autoroller recipe: pub_autoroller/pub_autoroller
bringup: true # https://github.com/flutter/flutter/issues/160473
# This takes a while because we need to fetch network dependencies and run # This takes a while because we need to fetch network dependencies and run
# Gradle for every android app in the repo # Gradle for every android app in the repo
timeout: 45 timeout: 45

View File

@ -1,15 +1,6 @@
// VSCode workspace settings that are shared among all users of this project. // VSCode workspace settings that are shared among all users of this project.
// This only affects subdirectories of this project. // This only affects subdirectories of this project.
{ {
// VSCode formats files on save by default. Since Flutter source code is
// hand-formatted, the default settings are changed to prevent inadvertent
// reformatting of code.
"[dart]": {
"editor.formatOnSave": false,
"editor.formatOnType": false,
"editor.formatOnPaste": false,
},
"html.format.enable": false, "html.format.enable": false,
"githubPullRequests.ignoredPullRequestBranches": [ "githubPullRequests.ignoredPullRequestBranches": [
"master" "master"

View File

@ -12,10 +12,6 @@ class DynamicTitle extends StatelessWidget {
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
return Title( return Title(title: title, color: Theme.of(context).colorScheme.primary, child: child);
title: title,
color: Theme.of(context).colorScheme.primary,
child: child,
);
} }
} }

View File

@ -21,21 +21,26 @@ class App extends StatelessWidget {
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
final ThemeData lightTheme = ThemeData( final ThemeData lightTheme = ThemeData(
colorScheme: ColorScheme.fromSeed( colorScheme: ColorScheme.fromSeed(
seedColor: const Color(0xff6750a4), seedColor: const Color(0xff6750a4),
contrastLevel: MediaQuery.highContrastOf(context) ? 1.0 : 0.0, contrastLevel: MediaQuery.highContrastOf(context) ? 1.0 : 0.0,
)); ),
);
final ThemeData darkTheme = ThemeData( final ThemeData darkTheme = ThemeData(
colorScheme: ColorScheme.fromSeed( colorScheme: ColorScheme.fromSeed(
brightness: Brightness.dark, brightness: Brightness.dark,
seedColor: const Color(0xff6750a4), seedColor: const Color(0xff6750a4),
contrastLevel: MediaQuery.highContrastOf(context) ? 1.0 : 0.0, contrastLevel: MediaQuery.highContrastOf(context) ? 1.0 : 0.0,
)); ),
);
final Map<String, WidgetBuilder> routes = final Map<String, WidgetBuilder> routes = Map<String, WidgetBuilder>.fromEntries(
Map<String, WidgetBuilder>.fromEntries( useCases.map(
useCases.map((UseCase useCase) => (UseCase useCase) => MapEntry<String, WidgetBuilder>(
MapEntry<String, WidgetBuilder>(useCase.route, (BuildContext context) => useCase.buildWithTitle(context))), useCase.route,
(BuildContext context) => useCase.buildWithTitle(context),
),
),
); );
return MaterialApp( return MaterialApp(
@ -65,22 +70,25 @@ class HomePageState extends State<HomePage> {
Widget _buildUseCaseItem(int index, UseCase useCase) { Widget _buildUseCaseItem(int index, UseCase useCase) {
return Padding( return Padding(
padding: const EdgeInsets.all(10), padding: const EdgeInsets.all(10),
child: Builder(builder: (BuildContext context) { child: Builder(
builder: (BuildContext context) {
return TextButton( return TextButton(
key: Key(useCase.name), key: Key(useCase.name),
onPressed: () => Navigator.of(context).pushNamed(useCase.route, arguments: useCase.name), onPressed:
() => Navigator.of(context).pushNamed(useCase.route, arguments: useCase.name),
child: Text(useCase.name), child: Text(useCase.name),
); );
})); },
),
);
} }
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
return Scaffold( return Scaffold(
appBar: AppBar( appBar: AppBar(
title: Semantics(headingLevel: 1, child: const Text('Accessibility Assessments')), title: Semantics(headingLevel: 1, child: const Text('Accessibility Assessments')),
), ),
body: Center( body: Center(
child: ListView( child: ListView(

View File

@ -34,7 +34,7 @@ class MainWidgetState extends State<MainWidget> {
return Scaffold( return Scaffold(
appBar: AppBar( appBar: AppBar(
backgroundColor: Theme.of(context).colorScheme.inversePrimary, backgroundColor: Theme.of(context).colorScheme.inversePrimary,
title: Semantics(headingLevel:1, child: Text('$pageTitle Demo')), title: Semantics(headingLevel: 1, child: Text('$pageTitle Demo')),
), ),
body: Center( body: Center(
child: Column( child: Column(
@ -45,10 +45,7 @@ class MainWidgetState extends State<MainWidget> {
label: const Text('Action'), label: const Text('Action'),
onPressed: () {}, onPressed: () {},
), ),
const ActionChip( const ActionChip(avatar: Icon(Icons.favorite), label: Text('Action')),
avatar: Icon(Icons.favorite),
label: Text('Action'),
),
], ],
), ),
), ),

View File

@ -36,63 +36,58 @@ class MainWidgetState extends State<MainWidget> {
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
return Scaffold( return Scaffold(
appBar: <PreferredSizeWidget>[ appBar:
AppBar( <PreferredSizeWidget>[
backgroundColor: Theme.of(context).colorScheme.inversePrimary, AppBar(
title: Semantics(headingLevel: 1, child: const Text('AppBar')), backgroundColor: Theme.of(context).colorScheme.inversePrimary,
), title: Semantics(headingLevel: 1, child: const Text('AppBar')),
AppBar(
backgroundColor: Theme.of(context).colorScheme.inversePrimary,
title: Semantics(headingLevel: 1, child: const Text('AppBar')),
actions: <Widget>[
IconButton(
icon: const Icon(Icons.add_alert),
tooltip: 'Show Snackbar',
onPressed: () {
ScaffoldMessenger.of(context).showSnackBar(
const SnackBar(content: Text('This is a snackbar')));
},
), ),
IconButton( AppBar(
icon: const Icon(Icons.navigate_next), backgroundColor: Theme.of(context).colorScheme.inversePrimary,
tooltip: 'Go to the next page', title: Semantics(headingLevel: 1, child: const Text('AppBar')),
onPressed: () { actions: <Widget>[
Navigator.push(context, MaterialPageRoute<void>( IconButton(
builder: (BuildContext context) { icon: const Icon(Icons.add_alert),
return Scaffold( tooltip: 'Show Snackbar',
appBar: AppBar( onPressed: () {
backgroundColor: ScaffoldMessenger.of(
Theme.of(context).colorScheme.inversePrimary, context,
title: Semantics(headingLevel: 1, child: const Text('Next Page')), ).showSnackBar(const SnackBar(content: Text('This is a snackbar')));
), },
body: const Center( ),
child: Text( IconButton(
'This is the next page', icon: const Icon(Icons.navigate_next),
style: TextStyle(fontSize: 24), tooltip: 'Go to the next page',
), onPressed: () {
Navigator.push(
context,
MaterialPageRoute<void>(
builder: (BuildContext context) {
return Scaffold(
appBar: AppBar(
backgroundColor: Theme.of(context).colorScheme.inversePrimary,
title: Semantics(headingLevel: 1, child: const Text('Next Page')),
),
body: const Center(
child: Text('This is the next page', style: TextStyle(fontSize: 24)),
),
);
},
), ),
); );
}, },
)); ),
}, ],
), ),
], AppBar(
), backgroundColor: Theme.of(context).colorScheme.inversePrimary,
AppBar( title: Semantics(headingLevel: 1, child: const Text('AppBar')),
backgroundColor: Theme.of(context).colorScheme.inversePrimary, actions: <Widget>[
title: Semantics(headingLevel: 1, child: const Text('AppBar')), TextButton(onPressed: () {}, child: const Text('Action 1')),
actions: <Widget>[ TextButton(onPressed: () {}, child: const Text('Action 2')),
TextButton( ],
onPressed: () {},
child: const Text('Action 1'),
), ),
TextButton( ][currentIndex],
onPressed: () {},
child: const Text('Action 2'),
),
],
),
][currentIndex],
body: ListView( body: ListView(
children: <Widget>[ children: <Widget>[
RadioListTile<int>( RadioListTile<int>(

View File

@ -25,17 +25,14 @@ class _MainWidget extends StatefulWidget {
} }
class _MainWidgetState extends State<_MainWidget> { class _MainWidgetState extends State<_MainWidget> {
static const List<String> _kOptions = <String>[ static const List<String> _kOptions = <String>['apple', 'banana', 'lemon'];
'apple',
'banana',
'lemon',
];
static Widget _fieldViewBuilder( static Widget _fieldViewBuilder(
BuildContext context, BuildContext context,
TextEditingController textEditingController, TextEditingController textEditingController,
FocusNode focusNode, FocusNode focusNode,
VoidCallback onFieldSubmitted) { VoidCallback onFieldSubmitted,
) {
return TextFormField( return TextFormField(
focusNode: focusNode, focusNode: focusNode,
controller: textEditingController, controller: textEditingController,
@ -58,8 +55,7 @@ class _MainWidgetState extends State<_MainWidget> {
child: Column( child: Column(
mainAxisAlignment: MainAxisAlignment.center, mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[ children: <Widget>[
Text( Text('Type below to autocomplete the following possible results: $_kOptions.'),
'Type below to autocomplete the following possible results: $_kOptions.'),
Autocomplete<String>( Autocomplete<String>(
optionsBuilder: (TextEditingValue textEditingValue) { optionsBuilder: (TextEditingValue textEditingValue) {
if (textEditingValue.text == '') { if (textEditingValue.text == '') {

View File

@ -36,11 +36,7 @@ class MainWidgetState extends State<MainWidget> {
), ),
body: const Center( body: const Center(
child: Badge( child: Badge(
label: Text( label: Text('5', semanticsLabel: '5 new messages', style: TextStyle(color: Colors.white)),
'5',
semanticsLabel: '5 new messages',
style: TextStyle(color: Colors.white),
),
backgroundColor: Colors.green, backgroundColor: Colors.green,
child: Icon(Icons.mail, semanticLabel: 'Messages'), child: Icon(Icons.mail, semanticLabel: 'Messages'),
), ),

View File

@ -40,12 +40,7 @@ class MainWidgetState extends State<MainWidget> {
child: Column( child: Column(
mainAxisAlignment: MainAxisAlignment.center, mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[ children: <Widget>[
Card( Card(child: Padding(padding: EdgeInsets.all(16), child: Text('Card'))),
child: Padding(
padding: EdgeInsets.all(16),
child: Text('Card'),
),
),
], ],
), ),
), ),

View File

@ -30,9 +30,7 @@ class _MainWidgetState extends State<_MainWidget> {
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
return Scaffold( return Scaffold(
appBar: AppBar( appBar: AppBar(title: Semantics(headingLevel: 1, child: Text('$pageTitle Demo'))),
title: Semantics(headingLevel: 1, child: Text('$pageTitle Demo')),
),
body: ListView( body: ListView(
children: <Widget>[ children: <Widget>[
CheckboxListTile( CheckboxListTile(

View File

@ -25,7 +25,6 @@ class _MainWidget extends StatefulWidget {
} }
class _MainWidgetState extends State<_MainWidget> { class _MainWidgetState extends State<_MainWidget> {
String pageTitle = getUseCaseName(DatePickerUseCase()); String pageTitle = getUseCaseName(DatePickerUseCase());
@override @override
@ -37,13 +36,14 @@ class _MainWidgetState extends State<_MainWidget> {
), ),
body: Center( body: Center(
child: TextButton( child: TextButton(
onPressed: () => showDatePicker( onPressed:
context: context, () => showDatePicker(
initialEntryMode: DatePickerEntryMode.calendarOnly, context: context,
initialDate: DateTime.now(), initialEntryMode: DatePickerEntryMode.calendarOnly,
firstDate: DateTime.now().subtract(const Duration(days: 365)), initialDate: DateTime.now(),
lastDate: DateTime.now().add(const Duration(days: 365)), firstDate: DateTime.now().subtract(const Duration(days: 365)),
), lastDate: DateTime.now().add(const Duration(days: 365)),
),
child: const Text('Show Date Picker'), child: const Text('Show Date Picker'),
), ),
), ),

View File

@ -31,40 +31,42 @@ class _MainWidget extends StatelessWidget {
), ),
body: Center( body: Center(
child: TextButton( child: TextButton(
onPressed: () => showDialog<String>( onPressed:
context: context, () => showDialog<String>(
builder: (BuildContext context) => Dialog( context: context,
child: Padding( builder:
padding: const EdgeInsets.all(8.0), (BuildContext context) => Dialog(
child: Column( child: Padding(
mainAxisSize: MainAxisSize.min, padding: const EdgeInsets.all(8.0),
mainAxisAlignment: MainAxisAlignment.center, child: Column(
children: <Widget>[ mainAxisSize: MainAxisSize.min,
const Text('This is a typical dialog.'), mainAxisAlignment: MainAxisAlignment.center,
const SizedBox(height: 15), children: <Widget>[
Row( const Text('This is a typical dialog.'),
children: <Widget>[ const SizedBox(height: 15),
TextButton( Row(
key: const Key('OK Button'), children: <Widget>[
autofocus: true, TextButton(
onPressed: () { key: const Key('OK Button'),
Navigator.pop(context); autofocus: true,
}, onPressed: () {
child: const Text('OK'), Navigator.pop(context);
},
child: const Text('OK'),
),
TextButton(
onPressed: () {
Navigator.pop(context);
},
child: const Text('Cancel'),
),
],
),
],
), ),
TextButton( ),
onPressed: () {
Navigator.pop(context);
},
child: const Text('Cancel'),
),
],
), ),
],
),
), ),
),
),
child: const Text('Show Dialog'), child: const Text('Show Dialog'),
), ),
), ),

View File

@ -41,16 +41,8 @@ class _DrawerExampleState extends State<DrawerExample> {
padding: EdgeInsets.zero, padding: EdgeInsets.zero,
children: <Widget>[ children: <Widget>[
const DrawerHeader( const DrawerHeader(
decoration: BoxDecoration( decoration: BoxDecoration(color: Colors.blue),
color: Colors.blue, child: Text('Drawer Header', style: TextStyle(color: Colors.white, fontSize: 24)),
),
child: Text(
'Drawer Header',
style: TextStyle(
color: Colors.white,
fontSize: 24,
),
),
), ),
ListTile( ListTile(
leading: const Icon(Icons.message), leading: const Icon(Icons.message),
@ -82,9 +74,7 @@ class _DrawerExampleState extends State<DrawerExample> {
], ],
), ),
), ),
body: Center( body: Center(child: Text('Page: $selectedPage')),
child: Text('Page: $selectedPage'),
),
); );
} }
} }

View File

@ -41,9 +41,7 @@ class _ExpansionTileExampleState extends State<ExpansionTileExample> {
const ExpansionTile( const ExpansionTile(
title: Text('ExpansionTile 1'), title: Text('ExpansionTile 1'),
subtitle: Text('Trailing expansion arrow icon'), subtitle: Text('Trailing expansion arrow icon'),
children: <Widget>[ children: <Widget>[ListTile(title: Text('This is tile number 1'))],
ListTile(title: Text('This is tile number 1')),
],
), ),
ExpansionTile( ExpansionTile(
title: const Text('ExpansionTile 2'), title: const Text('ExpansionTile 2'),
@ -51,9 +49,7 @@ class _ExpansionTileExampleState extends State<ExpansionTileExample> {
trailing: Icon( trailing: Icon(
_customTileExpanded ? Icons.arrow_drop_down_circle : Icons.arrow_drop_down, _customTileExpanded ? Icons.arrow_drop_down_circle : Icons.arrow_drop_down,
), ),
children: const <Widget>[ children: const <Widget>[ListTile(title: Text('This is tile number 2'))],
ListTile(title: Text('This is tile number 2')),
],
onExpansionChanged: (bool expanded) { onExpansionChanged: (bool expanded) {
setState(() { setState(() {
_customTileExpanded = expanded; _customTileExpanded = expanded;
@ -64,9 +60,7 @@ class _ExpansionTileExampleState extends State<ExpansionTileExample> {
title: Text('ExpansionTile 3'), title: Text('ExpansionTile 3'),
subtitle: Text('Leading expansion arrow icon'), subtitle: Text('Leading expansion arrow icon'),
controlAffinity: ListTileControlAffinity.leading, controlAffinity: ListTileControlAffinity.leading,
children: <Widget>[ children: <Widget>[ListTile(title: Text('This is tile number 3'))],
ListTile(title: Text('This is tile number 3')),
],
), ),
], ],
), ),

View File

@ -25,7 +25,6 @@ class MainWidget extends StatefulWidget {
} }
class MainWidgetState extends State<MainWidget> { class MainWidgetState extends State<MainWidget> {
final FocusNode dismissButtonFocusNode = FocusNode(); final FocusNode dismissButtonFocusNode = FocusNode();
final FocusNode showButtonFocusNode = FocusNode(); final FocusNode showButtonFocusNode = FocusNode();
@ -64,7 +63,7 @@ class MainWidgetState extends State<MainWidget> {
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
return Scaffold( return Scaffold(
appBar: AppBar( appBar: AppBar(
backgroundColor: Theme.of(context).colorScheme.inversePrimary, backgroundColor: Theme.of(context).colorScheme.inversePrimary,
title: Semantics(headingLevel: 1, child: Text('$pageTitle Demo')), title: Semantics(headingLevel: 1, child: Text('$pageTitle Demo')),

View File

@ -50,10 +50,7 @@ class MainWidgetState extends State<MainWidget> {
icon: Icon(Icons.home_outlined), icon: Icon(Icons.home_outlined),
label: 'Home', label: 'Home',
), ),
NavigationDestination( NavigationDestination(icon: Icon(Icons.business), label: 'Business'),
icon: Icon(Icons.business),
label: 'Business',
),
NavigationDestination( NavigationDestination(
selectedIcon: Icon(Icons.school), selectedIcon: Icon(Icons.school),
icon: Icon(Icons.school_outlined), icon: Icon(Icons.school_outlined),
@ -61,20 +58,12 @@ class MainWidgetState extends State<MainWidget> {
), ),
], ],
), ),
body: <Widget>[ body:
Container( <Widget>[
alignment: Alignment.center, Container(alignment: Alignment.center, child: const Text('Page 1')),
child: const Text('Page 1'), Container(alignment: Alignment.center, child: const Text('Page 2')),
), Container(alignment: Alignment.center, child: const Text('Page 3')),
Container( ][currentPageIndex],
alignment: Alignment.center,
child: const Text('Page 2'),
),
Container(
alignment: Alignment.center,
child: const Text('Page 3'),
),
][currentPageIndex],
); );
} }
} }

View File

@ -2,12 +2,10 @@
// Use of this source code is governed by a BSD-style license that can be // Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file. // found in the LICENSE file.
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import '../utils.dart'; import '../utils.dart';
import 'use_cases.dart'; import 'use_cases.dart';
class ExampleDestination { class ExampleDestination {
const ExampleDestination(this.label, this.icon, this.selectedIcon); const ExampleDestination(this.label, this.icon, this.selectedIcon);
@ -17,12 +15,9 @@ class ExampleDestination {
} }
const List<ExampleDestination> destinations = <ExampleDestination>[ const List<ExampleDestination> destinations = <ExampleDestination>[
ExampleDestination( ExampleDestination('Messages', Icon(Icons.widgets_outlined), Icon(Icons.widgets)),
'Messages', Icon(Icons.widgets_outlined), Icon(Icons.widgets)), ExampleDestination('Profile', Icon(Icons.format_paint_outlined), Icon(Icons.format_paint)),
ExampleDestination( ExampleDestination('Settings', Icon(Icons.settings_outlined), Icon(Icons.settings)),
'Profile', Icon(Icons.format_paint_outlined), Icon(Icons.format_paint)),
ExampleDestination(
'Settings', Icon(Icons.settings_outlined), Icon(Icons.settings)),
]; ];
class NavigationDrawerUseCase extends UseCase { class NavigationDrawerUseCase extends UseCase {
@ -40,8 +35,7 @@ class NavigationDrawerExample extends StatefulWidget {
const NavigationDrawerExample({super.key}); const NavigationDrawerExample({super.key});
@override @override
State<NavigationDrawerExample> createState() => State<NavigationDrawerExample> createState() => _NavigationDrawerExampleState();
_NavigationDrawerExampleState();
} }
class _NavigationDrawerExampleState extends State<NavigationDrawerExample> { class _NavigationDrawerExampleState extends State<NavigationDrawerExample> {
@ -77,10 +71,7 @@ class _NavigationDrawerExampleState extends State<NavigationDrawerExample> {
mainAxisAlignment: MainAxisAlignment.spaceEvenly, mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: <Widget>[ children: <Widget>[
Text('Page Index = $screenIndex'), Text('Page Index = $screenIndex'),
ElevatedButton( ElevatedButton(onPressed: openDrawer, child: const Text('Open Drawer')),
onPressed: openDrawer,
child: const Text('Open Drawer'),
),
], ],
), ),
), ),
@ -91,24 +82,16 @@ class _NavigationDrawerExampleState extends State<NavigationDrawerExample> {
children: <Widget>[ children: <Widget>[
Padding( Padding(
padding: const EdgeInsets.fromLTRB(28, 16, 16, 10), padding: const EdgeInsets.fromLTRB(28, 16, 16, 10),
child: Text( child: Text('Header', style: Theme.of(context).textTheme.titleSmall),
'Header',
style: Theme.of(context).textTheme.titleSmall,
),
),
...destinations.map(
(ExampleDestination destination) {
return NavigationDrawerDestination(
label: Text(destination.label),
icon: destination.icon,
selectedIcon: destination.selectedIcon,
);
},
),
const Padding(
padding: EdgeInsets.fromLTRB(28, 16, 28, 10),
child: Divider(),
), ),
...destinations.map((ExampleDestination destination) {
return NavigationDrawerDestination(
label: Text(destination.label),
icon: destination.icon,
selectedIcon: destination.selectedIcon,
);
}),
const Padding(padding: EdgeInsets.fromLTRB(28, 16, 28, 10), child: Divider()),
], ],
), ),
); );

View File

@ -47,23 +47,25 @@ class _NavRailExampleState extends State<NavRailExample> {
}); });
}, },
labelType: labelType, labelType: labelType,
leading: showLeading leading:
? FloatingActionButton( showLeading
elevation: 0, ? FloatingActionButton(
onPressed: () { elevation: 0,
// Add your onPressed code here! onPressed: () {
}, // Add your onPressed code here!
child: const Icon(Icons.add), },
) child: const Icon(Icons.add),
: const SizedBox(), )
trailing: showTrailing : const SizedBox(),
? IconButton( trailing:
onPressed: () { showTrailing
// Add your onPressed code here! ? IconButton(
}, onPressed: () {
icon: const Icon(Icons.more_horiz_rounded), // Add your onPressed code here!
) },
: const SizedBox(), icon: const Icon(Icons.more_horiz_rounded),
)
: const SizedBox(),
destinations: const <NavigationRailDestination>[ destinations: const <NavigationRailDestination>[
NavigationRailDestination( NavigationRailDestination(
icon: Icon(Icons.favorite_border), icon: Icon(Icons.favorite_border),

View File

@ -38,9 +38,7 @@ class _MainWidgetState extends State<_MainWidget> {
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
return Scaffold( return Scaffold(
appBar: AppBar( appBar: AppBar(title: Semantics(headingLevel: 1, child: Text('$pageTitle Demo'))),
title: Semantics(headingLevel: 1, child: Text('$pageTitle Demo'))
),
body: ListView( body: ListView(
children: <Widget>[ children: <Widget>[
RadioListTile<SingingCharacter>( RadioListTile<SingingCharacter>(

View File

@ -25,7 +25,6 @@ class MainWidget extends StatefulWidget {
} }
class MainWidgetState extends State<MainWidget> { class MainWidgetState extends State<MainWidget> {
String pageTitle = getUseCaseName(SnackBarUseCase()); String pageTitle = getUseCaseName(SnackBarUseCase());
@override @override
@ -41,11 +40,9 @@ class MainWidgetState extends State<MainWidget> {
ElevatedButton( ElevatedButton(
child: const Text('Show Snackbar'), child: const Text('Show Snackbar'),
onPressed: () { onPressed: () {
ScaffoldMessenger.of(context).showSnackBar( ScaffoldMessenger.of(
const SnackBar( context,
content: Text('Awesome Snackbar!'), ).showSnackBar(const SnackBar(content: Text('Awesome Snackbar!')));
),
);
}, },
), ),
ElevatedButton( ElevatedButton(
@ -54,10 +51,7 @@ class MainWidgetState extends State<MainWidget> {
ScaffoldMessenger.of(context).showSnackBar( ScaffoldMessenger.of(context).showSnackBar(
SnackBar( SnackBar(
content: const Text('Awesome Snackbar!'), content: const Text('Awesome Snackbar!'),
action: SnackBarAction( action: SnackBarAction(label: 'Action', onPressed: () {}),
label: 'Action',
onPressed: () {},
),
), ),
); );
}, },

View File

@ -7,7 +7,6 @@ import 'package:flutter/material.dart';
import 'use_cases.dart'; import 'use_cases.dart';
class TabBarViewUseCase extends UseCase { class TabBarViewUseCase extends UseCase {
@override @override
String get name => 'TabBarView'; String get name => 'TabBarView';
@ -18,7 +17,6 @@ class TabBarViewUseCase extends UseCase {
Widget build(BuildContext context) => const TabBarViewExample(); Widget build(BuildContext context) => const TabBarViewExample();
} }
class TabBarViewExample extends StatelessWidget { class TabBarViewExample extends StatelessWidget {
const TabBarViewExample({super.key}); const TabBarViewExample({super.key});
@ -32,32 +30,17 @@ class TabBarViewExample extends StatelessWidget {
title: Semantics(headingLevel: 1, child: const Text('TabBarView Sample')), title: Semantics(headingLevel: 1, child: const Text('TabBarView Sample')),
bottom: const TabBar( bottom: const TabBar(
tabs: <Widget>[ tabs: <Widget>[
Tab( Tab(icon: Icon(Icons.cloud_outlined), text: 'Cloudy'),
icon: Icon(Icons.cloud_outlined), Tab(icon: Icon(Icons.beach_access_sharp), text: 'Rainy'),
text: 'Cloudy', Tab(icon: Icon(Icons.brightness_5_sharp), text: 'Sunny'),
),
Tab(
icon: Icon(Icons.beach_access_sharp),
text: 'Rainy',
),
Tab(
icon: Icon(Icons.brightness_5_sharp),
text: 'Sunny',
),
], ],
), ),
), ),
body: const TabBarView( body: const TabBarView(
children: <Widget>[ children: <Widget>[
Center( Center(child: Text("It's cloudy here")),
child: Text("It's cloudy here"), Center(child: Text("It's rainy here")),
), Center(child: Text("It's sunny here")),
Center(
child: Text("It's rainy here"),
),
Center(
child: Text("It's sunny here"),
),
], ],
), ),
), ),

View File

@ -57,12 +57,12 @@ class MainWidgetState extends State<MainWidget> {
if (_formKey.currentState!.validate()) { if (_formKey.currentState!.validate()) {
// If the form is valid, display a snackbar. In the real world, // If the form is valid, display a snackbar. In the real world,
// this might also send a request to a server. // this might also send a request to a server.
ScaffoldMessenger.of(context).showSnackBar( ScaffoldMessenger.of(
const SnackBar(content: Text('Form submitted')), context,
); ).showSnackBar(const SnackBar(content: Text('Form submitted')));
} }
}, },
child: const Text('Submit'), child: const Text('Submit'),
), ),
), ),
], ],

View File

@ -33,16 +33,12 @@ class _MainWidget extends StatelessWidget {
children: const <Widget>[ children: const <Widget>[
TextField( TextField(
key: Key('enabled password'), key: Key('enabled password'),
decoration: InputDecoration( decoration: InputDecoration(labelText: 'Password'),
labelText: 'Password',
),
obscureText: true, obscureText: true,
), ),
TextField( TextField(
key: Key('disabled password'), key: Key('disabled password'),
decoration: InputDecoration( decoration: InputDecoration(labelText: 'Password'),
labelText: 'Password',
),
enabled: false, enabled: false,
obscureText: true, obscureText: true,
), ),

View File

@ -33,10 +33,7 @@ abstract class UseCase {
String get route; String get route;
Widget buildWithTitle(BuildContext context) { Widget buildWithTitle(BuildContext context) {
return DynamicTitle( return DynamicTitle(title: name, child: build(context));
title: name,
child: build(context),
);
} }
Widget build(BuildContext context); Widget build(BuildContext context);

View File

@ -9,8 +9,7 @@ import 'package:flutter_test/flutter_test.dart';
void main() { void main() {
for (final UseCase useCase in useCases) { for (final UseCase useCase in useCases) {
testWidgets('testing accessibility guideline for ${useCase.name}', testWidgets('testing accessibility guideline for ${useCase.name}', (WidgetTester tester) async {
(WidgetTester tester) async {
await tester.pumpWidget(const App()); await tester.pumpWidget(const App());
final ScrollController controller = final ScrollController controller =
tester.state<HomePageState>(find.byType(HomePage)).scrollController; tester.state<HomePageState>(find.byType(HomePage)).scrollController;

View File

@ -8,8 +8,7 @@ import 'package:flutter_test/flutter_test.dart';
import 'test_utils.dart'; import 'test_utils.dart';
void main() { void main() {
testWidgets('check box list tile use-case renders check boxes', testWidgets('check box list tile use-case renders check boxes', (WidgetTester tester) async {
(WidgetTester tester) async {
await pumpsUseCase(tester, CheckBoxListTile()); await pumpsUseCase(tester, CheckBoxListTile());
expect(find.text('a check box list title'), findsOneWidget); expect(find.text('a check box list title'), findsOneWidget);
expect(find.text('a disabled check box list title'), findsOneWidget); expect(find.text('a disabled check box list title'), findsOneWidget);

View File

@ -35,278 +35,391 @@ import 'test_utils.dart';
void main() { void main() {
testWidgets('Has light and dark theme', (WidgetTester tester) async { testWidgets('Has light and dark theme', (WidgetTester tester) async {
await tester.pumpWidget(const App()); await tester.pumpWidget(const App());
final MaterialApp app = final MaterialApp app = find.byType(MaterialApp).evaluate().first.widget as MaterialApp;
find.byType(MaterialApp).evaluate().first.widget as MaterialApp;
expect(app.theme!.brightness, equals(Brightness.light)); expect(app.theme!.brightness, equals(Brightness.light));
expect(app.darkTheme!.brightness, equals(Brightness.dark)); expect(app.darkTheme!.brightness, equals(Brightness.dark));
}); });
testWidgets('App can generate high-contrast color scheme', testWidgets('App can generate high-contrast color scheme', (WidgetTester tester) async {
(WidgetTester tester) async { await tester.pumpWidget(
await tester.pumpWidget(const MediaQuery( const MediaQuery(data: MediaQueryData(highContrast: true), child: App()),
data: MediaQueryData( );
highContrast: true,
),
child: App()));
final MaterialApp app = final MaterialApp app = find.byType(MaterialApp).evaluate().first.widget as MaterialApp;
find.byType(MaterialApp).evaluate().first.widget as MaterialApp;
final DynamicScheme highContrastScheme = SchemeTonalSpot( final DynamicScheme highContrastScheme = SchemeTonalSpot(
sourceColorHct: Hct.fromInt(const Color(0xff6750a4).value), sourceColorHct: Hct.fromInt(const Color(0xff6750a4).value),
isDark: false, isDark: false,
contrastLevel: 1.0); contrastLevel: 1.0,
);
final ColorScheme appScheme = app.theme!.colorScheme; final ColorScheme appScheme = app.theme!.colorScheme;
expect(appScheme.primary.value, expect(appScheme.primary.value, MaterialDynamicColors.primary.getArgb(highContrastScheme));
MaterialDynamicColors.primary.getArgb(highContrastScheme)); expect(appScheme.onPrimary.value, MaterialDynamicColors.onPrimary.getArgb(highContrastScheme));
expect(appScheme.onPrimary.value,
MaterialDynamicColors.onPrimary.getArgb(highContrastScheme));
expect(appScheme.primaryContainer.value,
MaterialDynamicColors.primaryContainer.getArgb(highContrastScheme));
expect(appScheme.onPrimaryContainer.value,
MaterialDynamicColors.onPrimaryContainer.getArgb(highContrastScheme));
expect(appScheme.primaryFixed.value,
MaterialDynamicColors.primaryFixed.getArgb(highContrastScheme));
expect(appScheme.primaryFixedDim.value,
MaterialDynamicColors.primaryFixedDim.getArgb(highContrastScheme));
expect(appScheme.onPrimaryFixed.value,
MaterialDynamicColors.onPrimaryFixed.getArgb(highContrastScheme));
expect( expect(
appScheme.onPrimaryFixedVariant.value, appScheme.primaryContainer.value,
MaterialDynamicColors.onPrimaryFixedVariant MaterialDynamicColors.primaryContainer.getArgb(highContrastScheme),
.getArgb(highContrastScheme)); );
expect(appScheme.secondary.value,
MaterialDynamicColors.secondary.getArgb(highContrastScheme));
expect(appScheme.onSecondary.value,
MaterialDynamicColors.onSecondary.getArgb(highContrastScheme));
expect(appScheme.secondaryContainer.value,
MaterialDynamicColors.secondaryContainer.getArgb(highContrastScheme));
expect(appScheme.onSecondaryContainer.value,
MaterialDynamicColors.onSecondaryContainer.getArgb(highContrastScheme));
expect(appScheme.secondaryFixed.value,
MaterialDynamicColors.secondaryFixed.getArgb(highContrastScheme));
expect(appScheme.secondaryFixedDim.value,
MaterialDynamicColors.secondaryFixedDim.getArgb(highContrastScheme));
expect(appScheme.onSecondaryFixed.value,
MaterialDynamicColors.onSecondaryFixed.getArgb(highContrastScheme));
expect( expect(
appScheme.onSecondaryFixedVariant.value, appScheme.onPrimaryContainer.value,
MaterialDynamicColors.onSecondaryFixedVariant MaterialDynamicColors.onPrimaryContainer.getArgb(highContrastScheme),
.getArgb(highContrastScheme)); );
expect(appScheme.tertiary.value,
MaterialDynamicColors.tertiary.getArgb(highContrastScheme));
expect(appScheme.onTertiary.value,
MaterialDynamicColors.onTertiary.getArgb(highContrastScheme));
expect(appScheme.tertiaryContainer.value,
MaterialDynamicColors.tertiaryContainer.getArgb(highContrastScheme));
expect(appScheme.onTertiaryContainer.value,
MaterialDynamicColors.onTertiaryContainer.getArgb(highContrastScheme));
expect(appScheme.tertiaryFixed.value,
MaterialDynamicColors.tertiaryFixed.getArgb(highContrastScheme));
expect(appScheme.tertiaryFixedDim.value,
MaterialDynamicColors.tertiaryFixedDim.getArgb(highContrastScheme));
expect(appScheme.onTertiaryFixed.value,
MaterialDynamicColors.onTertiaryFixed.getArgb(highContrastScheme));
expect( expect(
appScheme.onTertiaryFixedVariant.value, appScheme.primaryFixed.value,
MaterialDynamicColors.onTertiaryFixedVariant MaterialDynamicColors.primaryFixed.getArgb(highContrastScheme),
.getArgb(highContrastScheme)); );
expect(appScheme.error.value,
MaterialDynamicColors.error.getArgb(highContrastScheme));
expect(appScheme.onError.value,
MaterialDynamicColors.onError.getArgb(highContrastScheme));
expect(appScheme.errorContainer.value,
MaterialDynamicColors.errorContainer.getArgb(highContrastScheme));
expect(appScheme.onErrorContainer.value,
MaterialDynamicColors.onErrorContainer.getArgb(highContrastScheme));
expect(appScheme.background.value,
MaterialDynamicColors.background.getArgb(highContrastScheme));
expect(appScheme.onBackground.value,
MaterialDynamicColors.onBackground.getArgb(highContrastScheme));
expect(appScheme.surface.value,
MaterialDynamicColors.surface.getArgb(highContrastScheme));
expect(appScheme.surfaceDim.value,
MaterialDynamicColors.surfaceDim.getArgb(highContrastScheme));
expect(appScheme.surfaceBright.value,
MaterialDynamicColors.surfaceBright.getArgb(highContrastScheme));
expect( expect(
appScheme.surfaceContainerLowest.value, appScheme.primaryFixedDim.value,
MaterialDynamicColors.surfaceContainerLowest MaterialDynamicColors.primaryFixedDim.getArgb(highContrastScheme),
.getArgb(highContrastScheme)); );
expect(appScheme.surfaceContainerLow.value,
MaterialDynamicColors.surfaceContainerLow.getArgb(highContrastScheme));
expect(appScheme.surfaceContainer.value,
MaterialDynamicColors.surfaceContainer.getArgb(highContrastScheme));
expect(appScheme.surfaceContainerHigh.value,
MaterialDynamicColors.surfaceContainerHigh.getArgb(highContrastScheme));
expect( expect(
appScheme.surfaceContainerHighest.value, appScheme.onPrimaryFixed.value,
MaterialDynamicColors.surfaceContainerHighest MaterialDynamicColors.onPrimaryFixed.getArgb(highContrastScheme),
.getArgb(highContrastScheme)); );
expect(appScheme.onSurface.value, expect(
MaterialDynamicColors.onSurface.getArgb(highContrastScheme)); appScheme.onPrimaryFixedVariant.value,
expect(appScheme.surfaceVariant.value, MaterialDynamicColors.onPrimaryFixedVariant.getArgb(highContrastScheme),
MaterialDynamicColors.surfaceVariant.getArgb(highContrastScheme)); );
expect(appScheme.onSurfaceVariant.value, expect(appScheme.secondary.value, MaterialDynamicColors.secondary.getArgb(highContrastScheme));
MaterialDynamicColors.onSurfaceVariant.getArgb(highContrastScheme)); expect(
expect(appScheme.outline.value, appScheme.onSecondary.value,
MaterialDynamicColors.outline.getArgb(highContrastScheme)); MaterialDynamicColors.onSecondary.getArgb(highContrastScheme),
expect(appScheme.outlineVariant.value, );
MaterialDynamicColors.outlineVariant.getArgb(highContrastScheme)); expect(
expect(appScheme.shadow.value, appScheme.secondaryContainer.value,
MaterialDynamicColors.shadow.getArgb(highContrastScheme)); MaterialDynamicColors.secondaryContainer.getArgb(highContrastScheme),
expect(appScheme.scrim.value, );
MaterialDynamicColors.scrim.getArgb(highContrastScheme)); expect(
expect(appScheme.inverseSurface.value, appScheme.onSecondaryContainer.value,
MaterialDynamicColors.inverseSurface.getArgb(highContrastScheme)); MaterialDynamicColors.onSecondaryContainer.getArgb(highContrastScheme),
expect(appScheme.onInverseSurface.value, );
MaterialDynamicColors.inverseOnSurface.getArgb(highContrastScheme)); expect(
expect(appScheme.inversePrimary.value, appScheme.secondaryFixed.value,
MaterialDynamicColors.inversePrimary.getArgb(highContrastScheme)); MaterialDynamicColors.secondaryFixed.getArgb(highContrastScheme),
);
expect(
appScheme.secondaryFixedDim.value,
MaterialDynamicColors.secondaryFixedDim.getArgb(highContrastScheme),
);
expect(
appScheme.onSecondaryFixed.value,
MaterialDynamicColors.onSecondaryFixed.getArgb(highContrastScheme),
);
expect(
appScheme.onSecondaryFixedVariant.value,
MaterialDynamicColors.onSecondaryFixedVariant.getArgb(highContrastScheme),
);
expect(appScheme.tertiary.value, MaterialDynamicColors.tertiary.getArgb(highContrastScheme));
expect(
appScheme.onTertiary.value,
MaterialDynamicColors.onTertiary.getArgb(highContrastScheme),
);
expect(
appScheme.tertiaryContainer.value,
MaterialDynamicColors.tertiaryContainer.getArgb(highContrastScheme),
);
expect(
appScheme.onTertiaryContainer.value,
MaterialDynamicColors.onTertiaryContainer.getArgb(highContrastScheme),
);
expect(
appScheme.tertiaryFixed.value,
MaterialDynamicColors.tertiaryFixed.getArgb(highContrastScheme),
);
expect(
appScheme.tertiaryFixedDim.value,
MaterialDynamicColors.tertiaryFixedDim.getArgb(highContrastScheme),
);
expect(
appScheme.onTertiaryFixed.value,
MaterialDynamicColors.onTertiaryFixed.getArgb(highContrastScheme),
);
expect(
appScheme.onTertiaryFixedVariant.value,
MaterialDynamicColors.onTertiaryFixedVariant.getArgb(highContrastScheme),
);
expect(appScheme.error.value, MaterialDynamicColors.error.getArgb(highContrastScheme));
expect(appScheme.onError.value, MaterialDynamicColors.onError.getArgb(highContrastScheme));
expect(
appScheme.errorContainer.value,
MaterialDynamicColors.errorContainer.getArgb(highContrastScheme),
);
expect(
appScheme.onErrorContainer.value,
MaterialDynamicColors.onErrorContainer.getArgb(highContrastScheme),
);
expect(
appScheme.background.value,
MaterialDynamicColors.background.getArgb(highContrastScheme),
);
expect(
appScheme.onBackground.value,
MaterialDynamicColors.onBackground.getArgb(highContrastScheme),
);
expect(appScheme.surface.value, MaterialDynamicColors.surface.getArgb(highContrastScheme));
expect(
appScheme.surfaceDim.value,
MaterialDynamicColors.surfaceDim.getArgb(highContrastScheme),
);
expect(
appScheme.surfaceBright.value,
MaterialDynamicColors.surfaceBright.getArgb(highContrastScheme),
);
expect(
appScheme.surfaceContainerLowest.value,
MaterialDynamicColors.surfaceContainerLowest.getArgb(highContrastScheme),
);
expect(
appScheme.surfaceContainerLow.value,
MaterialDynamicColors.surfaceContainerLow.getArgb(highContrastScheme),
);
expect(
appScheme.surfaceContainer.value,
MaterialDynamicColors.surfaceContainer.getArgb(highContrastScheme),
);
expect(
appScheme.surfaceContainerHigh.value,
MaterialDynamicColors.surfaceContainerHigh.getArgb(highContrastScheme),
);
expect(
appScheme.surfaceContainerHighest.value,
MaterialDynamicColors.surfaceContainerHighest.getArgb(highContrastScheme),
);
expect(appScheme.onSurface.value, MaterialDynamicColors.onSurface.getArgb(highContrastScheme));
expect(
appScheme.surfaceVariant.value,
MaterialDynamicColors.surfaceVariant.getArgb(highContrastScheme),
);
expect(
appScheme.onSurfaceVariant.value,
MaterialDynamicColors.onSurfaceVariant.getArgb(highContrastScheme),
);
expect(appScheme.outline.value, MaterialDynamicColors.outline.getArgb(highContrastScheme));
expect(
appScheme.outlineVariant.value,
MaterialDynamicColors.outlineVariant.getArgb(highContrastScheme),
);
expect(appScheme.shadow.value, MaterialDynamicColors.shadow.getArgb(highContrastScheme));
expect(appScheme.scrim.value, MaterialDynamicColors.scrim.getArgb(highContrastScheme));
expect(
appScheme.inverseSurface.value,
MaterialDynamicColors.inverseSurface.getArgb(highContrastScheme),
);
expect(
appScheme.onInverseSurface.value,
MaterialDynamicColors.inverseOnSurface.getArgb(highContrastScheme),
);
expect(
appScheme.inversePrimary.value,
MaterialDynamicColors.inversePrimary.getArgb(highContrastScheme),
);
}); });
testWidgets('Each A11y Assessments page has a unique page title.', (WidgetTester tester) async { testWidgets('Each A11y Assessments page has a unique page title.', (WidgetTester tester) async {
final List<MethodCall> log = <MethodCall>[]; final List<MethodCall> log = <MethodCall>[];
tester.binding.defaultBinaryMessenger.setMockMethodCallHandler(SystemChannels.platform, (MethodCall methodCall) async { tester.binding.defaultBinaryMessenger.setMockMethodCallHandler(SystemChannels.platform, (
MethodCall methodCall,
) async {
if (methodCall.method == 'SystemChrome.setApplicationSwitcherDescription') { if (methodCall.method == 'SystemChrome.setApplicationSwitcherDescription') {
log.add(methodCall); log.add(methodCall);
} }
return null; return null;
}); });
await tester.pumpWidget(Title( await tester.pumpWidget(
color: const Color(0xFF00FF00), Title(color: const Color(0xFF00FF00), title: 'Accessibility Assessments', child: Container()),
title: 'Accessibility Assessments', );
child: Container(), expect(
)); log[0],
expect(log[0], isMethodCall( isMethodCall(
'SystemChrome.setApplicationSwitcherDescription', 'SystemChrome.setApplicationSwitcherDescription',
arguments: <String, dynamic>{'label': 'Accessibility Assessments', 'primaryColor': 4278255360}, arguments: <String, dynamic>{
)); 'label': 'Accessibility Assessments',
'primaryColor': 4278255360,
},
),
);
await pumpsUseCase(tester, AutoCompleteUseCase()); await pumpsUseCase(tester, AutoCompleteUseCase());
expect(log[2], isMethodCall( expect(
'SystemChrome.setApplicationSwitcherDescription', log[2],
arguments: <String, dynamic>{'label': 'AutoComplete', 'primaryColor': 4284960932}, isMethodCall(
)); 'SystemChrome.setApplicationSwitcherDescription',
arguments: <String, dynamic>{'label': 'AutoComplete', 'primaryColor': 4284960932},
),
);
await pumpsUseCase(tester, ActionChipUseCase()); await pumpsUseCase(tester, ActionChipUseCase());
expect(log[4], isMethodCall( expect(
'SystemChrome.setApplicationSwitcherDescription', log[4],
arguments: <String, dynamic>{'label': 'ActionChip', 'primaryColor': 4284960932}, isMethodCall(
)); 'SystemChrome.setApplicationSwitcherDescription',
arguments: <String, dynamic>{'label': 'ActionChip', 'primaryColor': 4284960932},
),
);
await pumpsUseCase(tester, BadgeUseCase()); await pumpsUseCase(tester, BadgeUseCase());
expect(log[6], isMethodCall( expect(
'SystemChrome.setApplicationSwitcherDescription', log[6],
arguments: <String, dynamic>{'label': 'Badge', 'primaryColor': 4284960932}, isMethodCall(
)); 'SystemChrome.setApplicationSwitcherDescription',
arguments: <String, dynamic>{'label': 'Badge', 'primaryColor': 4284960932},
),
);
await pumpsUseCase(tester, CardUseCase()); await pumpsUseCase(tester, CardUseCase());
expect(log[8], isMethodCall( expect(
'SystemChrome.setApplicationSwitcherDescription', log[8],
arguments: <String, dynamic>{'label': 'Card', 'primaryColor': 4284960932}, isMethodCall(
)); 'SystemChrome.setApplicationSwitcherDescription',
arguments: <String, dynamic>{'label': 'Card', 'primaryColor': 4284960932},
),
);
await pumpsUseCase(tester, CheckBoxListTile()); await pumpsUseCase(tester, CheckBoxListTile());
expect(log[10], isMethodCall( expect(
'SystemChrome.setApplicationSwitcherDescription', log[10],
arguments: <String, dynamic>{'label': 'CheckBoxListTile', 'primaryColor': 4284960932}, isMethodCall(
)); 'SystemChrome.setApplicationSwitcherDescription',
arguments: <String, dynamic>{'label': 'CheckBoxListTile', 'primaryColor': 4284960932},
),
);
await pumpsUseCase(tester, DatePickerUseCase()); await pumpsUseCase(tester, DatePickerUseCase());
expect(log[12], isMethodCall( expect(
'SystemChrome.setApplicationSwitcherDescription', log[12],
arguments: <String, dynamic>{'label': 'DatePicker', 'primaryColor': 4284960932}, isMethodCall(
)); 'SystemChrome.setApplicationSwitcherDescription',
arguments: <String, dynamic>{'label': 'DatePicker', 'primaryColor': 4284960932},
),
);
await pumpsUseCase(tester, DialogUseCase()); await pumpsUseCase(tester, DialogUseCase());
expect(log[14], isMethodCall( expect(
'SystemChrome.setApplicationSwitcherDescription', log[14],
arguments: <String, dynamic>{'label': 'Dialog', 'primaryColor': 4284960932}, isMethodCall(
)); 'SystemChrome.setApplicationSwitcherDescription',
arguments: <String, dynamic>{'label': 'Dialog', 'primaryColor': 4284960932},
),
);
await pumpsUseCase(tester, ExpansionTileUseCase()); await pumpsUseCase(tester, ExpansionTileUseCase());
expect(log[16], isMethodCall( expect(
'SystemChrome.setApplicationSwitcherDescription', log[16],
arguments: <String, dynamic>{'label': 'ExpansionTile', 'primaryColor': 4284960932}, isMethodCall(
)); 'SystemChrome.setApplicationSwitcherDescription',
arguments: <String, dynamic>{'label': 'ExpansionTile', 'primaryColor': 4284960932},
),
);
await pumpsUseCase(tester, MaterialBannerUseCase()); await pumpsUseCase(tester, MaterialBannerUseCase());
expect(log[18], isMethodCall( expect(
'SystemChrome.setApplicationSwitcherDescription', log[18],
arguments: <String, dynamic>{'label': 'MaterialBanner', 'primaryColor': 4284960932}, isMethodCall(
)); 'SystemChrome.setApplicationSwitcherDescription',
arguments: <String, dynamic>{'label': 'MaterialBanner', 'primaryColor': 4284960932},
),
);
await pumpsUseCase(tester, NavigationBarUseCase()); await pumpsUseCase(tester, NavigationBarUseCase());
expect(log[20], isMethodCall( expect(
'SystemChrome.setApplicationSwitcherDescription', log[20],
arguments: <String, dynamic>{'label': 'NavigationBar', 'primaryColor': 4284960932}, isMethodCall(
)); 'SystemChrome.setApplicationSwitcherDescription',
arguments: <String, dynamic>{'label': 'NavigationBar', 'primaryColor': 4284960932},
),
);
await pumpsUseCase(tester, RadioListTileUseCase()); await pumpsUseCase(tester, RadioListTileUseCase());
expect(log[22], isMethodCall( expect(
'SystemChrome.setApplicationSwitcherDescription', log[22],
arguments: <String, dynamic>{'label': 'RadioListTile', 'primaryColor': 4284960932}, isMethodCall(
)); 'SystemChrome.setApplicationSwitcherDescription',
arguments: <String, dynamic>{'label': 'RadioListTile', 'primaryColor': 4284960932},
),
);
await pumpsUseCase(tester, SliderUseCase()); await pumpsUseCase(tester, SliderUseCase());
expect(log[24], isMethodCall( expect(
'SystemChrome.setApplicationSwitcherDescription', log[24],
arguments: <String, dynamic>{'label': 'Slider', 'primaryColor': 4284960932}, isMethodCall(
)); 'SystemChrome.setApplicationSwitcherDescription',
arguments: <String, dynamic>{'label': 'Slider', 'primaryColor': 4284960932},
),
);
await pumpsUseCase(tester, SnackBarUseCase()); await pumpsUseCase(tester, SnackBarUseCase());
expect(log[26], isMethodCall( expect(
'SystemChrome.setApplicationSwitcherDescription', log[26],
arguments: <String, dynamic>{'label': 'SnackBar', 'primaryColor': 4284960932}, isMethodCall(
)); 'SystemChrome.setApplicationSwitcherDescription',
arguments: <String, dynamic>{'label': 'SnackBar', 'primaryColor': 4284960932},
),
);
await pumpsUseCase(tester, SwitchListTileUseCase()); await pumpsUseCase(tester, SwitchListTileUseCase());
expect(log[28], isMethodCall( expect(
'SystemChrome.setApplicationSwitcherDescription', log[28],
arguments: <String, dynamic>{'label': 'SwitchListTile', 'primaryColor': 4284960932}, isMethodCall(
)); 'SystemChrome.setApplicationSwitcherDescription',
arguments: <String, dynamic>{'label': 'SwitchListTile', 'primaryColor': 4284960932},
),
);
await pumpsUseCase(tester, TextButtonUseCase()); await pumpsUseCase(tester, TextButtonUseCase());
expect(log[30], isMethodCall( expect(
'SystemChrome.setApplicationSwitcherDescription', log[30],
arguments: <String, dynamic>{'label': 'TextButton', 'primaryColor': 4284960932}, isMethodCall(
)); 'SystemChrome.setApplicationSwitcherDescription',
arguments: <String, dynamic>{'label': 'TextButton', 'primaryColor': 4284960932},
),
);
await pumpsUseCase(tester, TextFieldUseCase()); await pumpsUseCase(tester, TextFieldUseCase());
expect(log[32], isMethodCall( expect(
'SystemChrome.setApplicationSwitcherDescription', log[32],
arguments: <String, dynamic>{'label': 'TextField', 'primaryColor': 4284960932}, isMethodCall(
)); 'SystemChrome.setApplicationSwitcherDescription',
arguments: <String, dynamic>{'label': 'TextField', 'primaryColor': 4284960932},
),
);
await pumpsUseCase(tester, TextFieldPasswordUseCase()); await pumpsUseCase(tester, TextFieldPasswordUseCase());
expect(log[34], isMethodCall( expect(
'SystemChrome.setApplicationSwitcherDescription', log[34],
arguments: <String, dynamic>{'label': 'TextField password', 'primaryColor': 4284960932}, isMethodCall(
)); 'SystemChrome.setApplicationSwitcherDescription',
arguments: <String, dynamic>{'label': 'TextField password', 'primaryColor': 4284960932},
),
);
await pumpsUseCase(tester, NavigationDrawerUseCase()); await pumpsUseCase(tester, NavigationDrawerUseCase());
expect(log[36], isMethodCall( expect(
'SystemChrome.setApplicationSwitcherDescription', log[36],
arguments: <String, dynamic>{'label': 'NavigationDrawer', 'primaryColor': 4284960932}, isMethodCall(
)); 'SystemChrome.setApplicationSwitcherDescription',
arguments: <String, dynamic>{'label': 'NavigationDrawer', 'primaryColor': 4284960932},
),
);
await pumpsUseCase(tester, NavigationRailUseCase()); await pumpsUseCase(tester, NavigationRailUseCase());
expect(log[38], isMethodCall( expect(
'SystemChrome.setApplicationSwitcherDescription', log[38],
arguments: <String, dynamic>{'label': 'NavigationRail', 'primaryColor': 4284960932}, isMethodCall(
)); 'SystemChrome.setApplicationSwitcherDescription',
arguments: <String, dynamic>{'label': 'NavigationRail', 'primaryColor': 4284960932},
),
);
await pumpsUseCase(tester, DrawerUseCase()); await pumpsUseCase(tester, DrawerUseCase());
expect(log[40], isMethodCall( expect(
'SystemChrome.setApplicationSwitcherDescription', log[40],
arguments: <String, dynamic>{'label': 'drawer', 'primaryColor': 4284960932}, isMethodCall(
)); 'SystemChrome.setApplicationSwitcherDescription',
arguments: <String, dynamic>{'label': 'drawer', 'primaryColor': 4284960932},
),
);
}); });
testWidgets('a11y assessments home page has one h1 tag', (WidgetTester tester) async { testWidgets('a11y assessments home page has one h1 tag', (WidgetTester tester) async {

View File

@ -38,7 +38,9 @@ void main() {
await tester.tap(find.byType(TextButton)); await tester.tap(find.byType(TextButton));
final ElevatedButton showButtonFinder = tester.widget<ElevatedButton>(find.byType(ElevatedButton)); final ElevatedButton showButtonFinder = tester.widget<ElevatedButton>(
find.byType(ElevatedButton),
);
expect(showButtonFinder.focusNode!.hasFocus, isTrue); expect(showButtonFinder.focusNode!.hasFocus, isTrue);
}); });

View File

@ -8,8 +8,7 @@ import 'package:flutter_test/flutter_test.dart';
import 'test_utils.dart'; import 'test_utils.dart';
void main() { void main() {
testWidgets('radio list tile use-case renders radio buttons', testWidgets('radio list tile use-case renders radio buttons', (WidgetTester tester) async {
(WidgetTester tester) async {
await pumpsUseCase(tester, RadioListTileUseCase()); await pumpsUseCase(tester, RadioListTileUseCase());
expect(find.text('Lafayette'), findsOneWidget); expect(find.text('Lafayette'), findsOneWidget);
expect(find.text('Jefferson'), findsOneWidget); expect(find.text('Jefferson'), findsOneWidget);

View File

@ -16,14 +16,12 @@ void main() {
await tester.tapAt(tester.getCenter(find.byType(Slider))); await tester.tapAt(tester.getCenter(find.byType(Slider)));
await tester.pumpAndSettle(); await tester.pumpAndSettle();
final MainWidgetState state = final MainWidgetState state = tester.state<MainWidgetState>(find.byType(MainWidget));
tester.state<MainWidgetState>(find.byType(MainWidget));
expect(state.currentSliderValue, 60); expect(state.currentSliderValue, 60);
}); });
testWidgets('slider semantics wrapper exists', (WidgetTester tester) async { testWidgets('slider semantics wrapper exists', (WidgetTester tester) async {
await pumpsUseCase(tester, SliderUseCase()); await pumpsUseCase(tester, SliderUseCase());
final Finder semanticsWidget = final Finder semanticsWidget = find.bySemanticsLabel('Accessibility Test Slider');
find.bySemanticsLabel('Accessibility Test Slider');
expect(semanticsWidget, findsOneWidget); expect(semanticsWidget, findsOneWidget);
}); });

View File

@ -7,11 +7,13 @@ import 'package:flutter/material.dart';
import 'package:flutter_test/flutter_test.dart'; import 'package:flutter_test/flutter_test.dart';
Future<void> pumpsUseCase(WidgetTester tester, UseCase useCase) async { Future<void> pumpsUseCase(WidgetTester tester, UseCase useCase) async {
await tester.pumpWidget(MaterialApp( await tester.pumpWidget(
home: Builder( MaterialApp(
builder: (BuildContext context) { home: Builder(
return useCase.buildWithTitle(context); builder: (BuildContext context) {
}, return useCase.buildWithTitle(context);
},
),
), ),
)); );
} }

View File

@ -31,8 +31,7 @@ void main() {
} }
}); });
testWidgets('text field passwords do not have hint text', testWidgets('text field passwords do not have hint text', (WidgetTester tester) async {
(WidgetTester tester) async {
await pumpsUseCase(tester, TextFieldPasswordUseCase()); await pumpsUseCase(tester, TextFieldPasswordUseCase());
expect(find.byType(TextField), findsExactly(2)); expect(find.byType(TextField), findsExactly(2));

View File

@ -31,20 +31,21 @@ void main() {
} }
}); });
testWidgets('font size increase does not ellipsize hint text', testWidgets('font size increase does not ellipsize hint text', (WidgetTester tester) async {
(WidgetTester tester) async {
await pumpsUseCase(tester, TextFieldUseCase()); await pumpsUseCase(tester, TextFieldUseCase());
await tester.pumpWidget(MaterialApp( await tester.pumpWidget(
home: MediaQuery.withClampedTextScaling( MaterialApp(
minScaleFactor: 3, home: MediaQuery.withClampedTextScaling(
maxScaleFactor: 3, minScaleFactor: 3,
child: Builder( maxScaleFactor: 3,
builder: (BuildContext context) { child: Builder(
return TextFieldUseCase().build(context); builder: (BuildContext context) {
}, return TextFieldUseCase().build(context);
},
),
), ),
), ),
)); );
// Test the enabled text field // Test the enabled text field
{ {
final Finder finder = find.byKey(const Key('enabled text field')); final Finder finder = find.byKey(const Key('enabled text field'));
@ -60,8 +61,7 @@ void main() {
await pumpsUseCase(tester, TextFieldUseCase()); await pumpsUseCase(tester, TextFieldUseCase());
const String textFieldLabel = 'Input field with suffix @gmail.com'; const String textFieldLabel = 'Input field with suffix @gmail.com';
final Finder semanticsWidgets = final Finder semanticsWidgets = find.bySemanticsLabel(RegExp(textFieldLabel));
find.bySemanticsLabel(RegExp(textFieldLabel));
expect(semanticsWidgets, findsExactly(2)); expect(semanticsWidgets, findsExactly(2));
}); });

View File

@ -5,5 +5,5 @@
import 'package:test/test.dart' hide TypeMatcher, isInstanceOf; import 'package:test/test.dart' hide TypeMatcher, isInstanceOf;
void main() { void main() {
test('trivial', () { }); test('trivial', () {});
} }

View File

@ -5,5 +5,5 @@
import 'package:test/test.dart' hide TypeMatcher, isInstanceOf; import 'package:test/test.dart' hide TypeMatcher, isInstanceOf;
void main() { void main() {
test('trivial', () { }); test('trivial', () {});
} }

View File

@ -14,26 +14,91 @@ import 'package:platform/platform.dart';
// 1x1 colored pixel // 1x1 colored pixel
const List<int> _kFailPngBytes = <int>[ const List<int> _kFailPngBytes = <int>[
137, 80, 78, 71, 13, 10, 26, 10, 0, 0, 0, 137,
13, 73, 72, 68, 82, 0, 0, 0, 1, 0, 0, 0, 1, 8, 6, 0, 0, 0, 31, 21, 196, 137, 80,
0, 0, 0, 13, 73, 68, 65, 84, 120, 1, 99, 249, 207, 240, 255, 63, 0, 7, 18, 3, 78,
2, 164, 147, 160, 197, 0, 0, 0, 0, 73, 69, 78, 68, 174, 66, 96, 130, 71,
13,
10,
26,
10,
0,
0,
0,
13,
73,
72,
68,
82,
0,
0,
0,
1,
0,
0,
0,
1,
8,
6,
0,
0,
0,
31,
21,
196,
137,
0,
0,
0,
13,
73,
68,
65,
84,
120,
1,
99,
249,
207,
240,
255,
63,
0,
7,
18,
3,
2,
164,
147,
160,
197,
0,
0,
0,
0,
73,
69,
78,
68,
174,
66,
96,
130,
]; ];
void main() { void main() {
final List<String> log = <String>[]; final List<String> log = <String>[];
final MemoryFileSystem fs = MemoryFileSystem(); final MemoryFileSystem fs = MemoryFileSystem();
final Directory basedir = fs.directory('flutter/test/library/') final Directory basedir = fs.directory('flutter/test/library/')..createSync(recursive: true);
..createSync(recursive: true); final FakeSkiaGoldClient fakeSkiaClient =
final FakeSkiaGoldClient fakeSkiaClient = FakeSkiaGoldClient() FakeSkiaGoldClient()..expectationForTestValues['flutter.new_golden_test.1'] = '';
..expectationForTestValues['flutter.new_golden_test.1'] = '';
final FlutterLocalFileComparator comparator = FlutterLocalFileComparator( final FlutterLocalFileComparator comparator = FlutterLocalFileComparator(
basedir.uri, basedir.uri,
fakeSkiaClient, fakeSkiaClient,
fs: fs, fs: fs,
platform: FakePlatform( platform: FakePlatform(
environment: <String, String>{'FLUTTER_ROOT': '/flutter'}, environment: <String, String>{'FLUTTER_ROOT': '/flutter'},
operatingSystem: 'macos' operatingSystem: 'macos',
), ),
log: log.add, log: log.add,
); );
@ -48,9 +113,9 @@ void main() {
isTrue, isTrue,
); );
const String expectation = const String expectation =
'No expectations provided by Skia Gold for test: library.flutter.new_golden_test.1.png. ' 'No expectations provided by Skia Gold for test: library.flutter.new_golden_test.1.png. '
'This may be a new test. If this is an unexpected result, check https://flutter-gold.skia.org.\n' 'This may be a new test. If this is an unexpected result, check https://flutter-gold.skia.org.\n'
'Validate image output found at flutter/test/library/'; 'Validate image output found at flutter/test/library/';
expect(log, const <String>[expectation]); expect(log, const <String>[expectation]);
}); });
@ -64,9 +129,9 @@ void main() {
isTrue, isTrue,
); );
const String expectation = const String expectation =
'No expectations provided by Skia Gold for test: library.flutter.new_golden_test.2.png. ' 'No expectations provided by Skia Gold for test: library.flutter.new_golden_test.2.png. '
'This may be a new test. If this is an unexpected result, check https://flutter-gold.skia.org.\n' 'This may be a new test. If this is an unexpected result, check https://flutter-gold.skia.org.\n'
'Validate image output found at flutter/test/library/'; 'Validate image output found at flutter/test/library/';
expect(log, const <String>[expectation]); expect(log, const <String>[expectation]);
}); });
} }

View File

@ -8,12 +8,6 @@ import 'package:flutter_test/flutter_test.dart';
void main() { void main() {
testWidgets('Rendering Error', (WidgetTester tester) async { testWidgets('Rendering Error', (WidgetTester tester) async {
// Assets can load with its package name. // Assets can load with its package name.
await tester.pumpWidget( await tester.pumpWidget(Image.asset('icon/test.png', width: 54, height: 54, fit: BoxFit.none));
Image.asset('icon/test.png',
width: 54,
height: 54,
fit: BoxFit.none,
),
);
}); });
} }

View File

@ -12,9 +12,7 @@ void main() {
MaterialApp( MaterialApp(
theme: ThemeData(useMaterial3: false), theme: ThemeData(useMaterial3: false),
home: Scaffold( home: Scaffold(
appBar: AppBar( appBar: AppBar(title: const Text('RenderFlex OverFlow')),
title: const Text('RenderFlex OverFlow'),
),
body: const SizedBox( body: const SizedBox(
width: 400.0, width: 400.0,
child: Row( child: Row(
@ -30,7 +28,7 @@ void main() {
'do eiusmod tempor incididunt ut labore et dolore magna ' 'do eiusmod tempor incididunt ut labore et dolore magna '
'aliqua. Ut enim ad minim veniam, quis nostrud ' 'aliqua. Ut enim ad minim veniam, quis nostrud '
'exercitation ullamco laboris nisi ut aliquip ex ea ' 'exercitation ullamco laboris nisi ut aliquip ex ea '
'commodo consequat.' 'commodo consequat.',
), ),
], ],
), ),
@ -38,7 +36,7 @@ void main() {
), ),
), ),
), ),
) ),
); );
}); });
} }

View File

@ -9,11 +9,7 @@ void main() {
testWidgets('Rendering Error', (WidgetTester tester) async { testWidgets('Rendering Error', (WidgetTester tester) async {
// this should fail // this should fail
await tester.pumpWidget( await tester.pumpWidget(
CustomScrollView( CustomScrollView(slivers: <Widget>[SliverToBoxAdapter(child: Container())]),
slivers: <Widget>[
SliverToBoxAdapter(child: Container()),
],
)
); );
}); });
} }

View File

@ -9,11 +9,7 @@ void main() {
testWidgets('Rendering Error', (WidgetTester tester) async { testWidgets('Rendering Error', (WidgetTester tester) async {
// this should fail // this should fail
await tester.pumpWidget( await tester.pumpWidget(
CustomScrollView( CustomScrollView(slivers: <Widget>[SliverToBoxAdapter(child: Container())]),
slivers: <Widget>[
SliverToBoxAdapter(child: Container()),
],
)
); );
}); });
} }

View File

@ -9,7 +9,9 @@ import 'package:flutter_test/flutter_test.dart';
class TestTestBinding extends AutomatedTestWidgetsFlutterBinding { class TestTestBinding extends AutomatedTestWidgetsFlutterBinding {
@override @override
DebugPrintCallback get debugPrintOverride => testPrint; DebugPrintCallback get debugPrintOverride => testPrint;
static void testPrint(String? message, { int? wrapWidth }) { print(message); } static void testPrint(String? message, {int? wrapWidth}) {
print(message);
}
} }
Future<void> guardedHelper(WidgetTester tester) { Future<void> guardedHelper(WidgetTester tester) {

View File

@ -8,7 +8,9 @@ import 'package:flutter_test/flutter_test.dart';
class TestTestBinding extends AutomatedTestWidgetsFlutterBinding { class TestTestBinding extends AutomatedTestWidgetsFlutterBinding {
@override @override
DebugPrintCallback get debugPrintOverride => testPrint; DebugPrintCallback get debugPrintOverride => testPrint;
static void testPrint(String? message, { int? wrapWidth }) { print(message); } static void testPrint(String? message, {int? wrapWidth}) {
print(message);
}
} }
Future<void> helperFunction(WidgetTester tester) async { Future<void> helperFunction(WidgetTester tester) async {
@ -17,7 +19,9 @@ Future<void> helperFunction(WidgetTester tester) async {
void main() { void main() {
TestTestBinding(); TestTestBinding();
testWidgets('TestAsyncUtils - handling unguarded async helper functions', (WidgetTester tester) async { testWidgets('TestAsyncUtils - handling unguarded async helper functions', (
WidgetTester tester,
) async {
helperFunction(tester); helperFunction(tester);
helperFunction(tester); helperFunction(tester);
// this should fail // this should fail

View File

@ -8,9 +8,13 @@ import 'package:flutter_test/flutter_test.dart';
void main() { void main() {
testWidgets('Does flutter_test catch leaking tickers?', (WidgetTester tester) async { testWidgets('Does flutter_test catch leaking tickers?', (WidgetTester tester) async {
Ticker((Duration duration) { }).start(); Ticker((Duration duration) {}).start();
final ByteData? message = const StringCodec().encodeMessage('AppLifecycleState.paused'); final ByteData? message = const StringCodec().encodeMessage('AppLifecycleState.paused');
await tester.binding.defaultBinaryMessenger.handlePlatformMessage('flutter/lifecycle', message, (_) {}); await tester.binding.defaultBinaryMessenger.handlePlatformMessage(
'flutter/lifecycle',
message,
(_) {},
);
}); });
} }

View File

@ -5,5 +5,5 @@
import 'package:test/test.dart' hide TypeMatcher, isInstanceOf; import 'package:test/test.dart' hide TypeMatcher, isInstanceOf;
void main() { void main() {
test('trivial', () { }); test('trivial', () {});
} }

View File

@ -13,7 +13,9 @@ void main() {
test('test smoke test -- this test should fail', () async { test('test smoke test -- this test should fail', () async {
if (system.Process.killPid(system.pid, system.ProcessSignal.sigsegv)) { if (system.Process.killPid(system.pid, system.ProcessSignal.sigsegv)) {
print('system.Process.killPid returned before the process ended!'); print('system.Process.killPid returned before the process ended!');
print('Sleeping for a few seconds just in case signal delivery is delayed or our signal handler is being slow...'); print(
'Sleeping for a few seconds just in case signal delivery is delayed or our signal handler is being slow...',
);
system.sleep(const Duration(seconds: 10)); // don't sleep too much, we must not time out system.sleep(const Duration(seconds: 10)); // don't sleep too much, we must not time out
} else { } else {
print('system.Process.killPid reports that the SIGSEGV signal was not delivered!'); print('system.Process.killPid reports that the SIGSEGV signal was not delivered!');

View File

@ -6,7 +6,5 @@ import 'package:flutter/widgets.dart';
import 'src/app.dart'; import 'src/app.dart';
void main() { void main() {
runApp( runApp(const ComplexLayoutApp());
const ComplexLayoutApp()
);
} }

View File

@ -6,7 +6,5 @@ import 'package:flutter/widgets.dart';
import 'src/app.dart'; import 'src/app.dart';
void main() { void main() {
runApp( runApp(const ComplexLayoutApp(badScroll: true));
const ComplexLayoutApp(badScroll: true)
);
} }

View File

@ -15,7 +15,8 @@ class ComplexLayoutApp extends StatefulWidget {
@override @override
ComplexLayoutAppState createState() => ComplexLayoutAppState(); ComplexLayoutAppState createState() => ComplexLayoutAppState();
static ComplexLayoutAppState? of(BuildContext context) => context.findAncestorStateOfType<ComplexLayoutAppState>(); static ComplexLayoutAppState? of(BuildContext context) =>
context.findAncestorStateOfType<ComplexLayoutAppState>();
} }
class ComplexLayoutAppState extends State<ComplexLayoutApp> { class ComplexLayoutAppState extends State<ComplexLayoutApp> {
@ -24,7 +25,11 @@ class ComplexLayoutAppState extends State<ComplexLayoutApp> {
return MaterialApp( return MaterialApp(
theme: lightTheme ? ThemeData.light() : ThemeData.dark(), theme: lightTheme ? ThemeData.light() : ThemeData.dark(),
title: 'Advanced Layout', title: 'Advanced Layout',
home: scrollMode == ScrollMode.complex ? ComplexLayout(badScroll: widget.badScroll) : const TileScrollLayout()); home:
scrollMode == ScrollMode.complex
? ComplexLayout(badScroll: widget.badScroll)
: const TileScrollLayout(),
);
} }
bool _lightTheme = true; bool _lightTheme = true;
@ -51,7 +56,7 @@ class ComplexLayoutAppState extends State<ComplexLayoutApp> {
} }
class TileScrollLayout extends StatelessWidget { class TileScrollLayout extends StatelessWidget {
const TileScrollLayout({ super.key }); const TileScrollLayout({super.key});
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
@ -77,14 +82,15 @@ class TileScrollLayout extends StatelessWidget {
} }
class ComplexLayout extends StatefulWidget { class ComplexLayout extends StatefulWidget {
const ComplexLayout({ super.key, required this.badScroll }); const ComplexLayout({super.key, required this.badScroll});
final bool badScroll; final bool badScroll;
@override @override
ComplexLayoutState createState() => ComplexLayoutState(); ComplexLayoutState createState() => ComplexLayoutState();
static ComplexLayoutState? of(BuildContext context) => context.findAncestorStateOfType<ComplexLayoutState>(); static ComplexLayoutState? of(BuildContext context) =>
context.findAncestorStateOfType<ComplexLayoutState>();
} }
class ComplexLayoutState extends State<ComplexLayout> { class ComplexLayoutState extends State<ComplexLayout> {
@ -92,7 +98,7 @@ class ComplexLayoutState extends State<ComplexLayout> {
Widget build(BuildContext context) { Widget build(BuildContext context) {
Widget body = ListView.builder( Widget body = ListView.builder(
key: const Key('complex-scroll'), // this key is used by the driver test key: const Key('complex-scroll'), // this key is used by the driver test
controller: ScrollController(), // So that the scroll offset can be tracked controller: ScrollController(), // So that the scroll offset can be tracked
itemCount: widget.badScroll ? 500 : null, itemCount: widget.badScroll ? 500 : null,
shrinkWrap: widget.badScroll, shrinkWrap: widget.badScroll,
itemBuilder: (BuildContext context, int index) { itemBuilder: (BuildContext context, int index) {
@ -104,10 +110,7 @@ class ComplexLayoutState extends State<ComplexLayout> {
}, },
); );
if (widget.badScroll) { if (widget.badScroll) {
body = ListView( body = ListView(key: const Key('complex-scroll-bad'), children: <Widget>[body]);
key: const Key('complex-scroll-bad'),
children: <Widget>[body],
);
} }
return Scaffold( return Scaffold(
@ -124,12 +127,7 @@ class ComplexLayoutState extends State<ComplexLayout> {
const TopBarMenu(), const TopBarMenu(),
], ],
), ),
body: Column( body: Column(children: <Widget>[Expanded(child: body), const BottomBar()]),
children: <Widget>[
Expanded(child: body),
const BottomBar(),
],
),
drawer: const GalleryDrawer(), drawer: const GalleryDrawer(),
); );
} }
@ -141,49 +139,52 @@ class TopBarMenu extends StatelessWidget {
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
return PopupMenuButton<String>( return PopupMenuButton<String>(
onSelected: (String value) { print('Selected: $value'); }, onSelected: (String value) {
itemBuilder: (BuildContext context) => <PopupMenuItem<String>>[ print('Selected: $value');
const PopupMenuItem<String>( },
value: 'Friends', itemBuilder:
child: MenuItemWithIcon(Icons.people, 'Friends', '5 new'), (BuildContext context) => <PopupMenuItem<String>>[
), const PopupMenuItem<String>(
const PopupMenuItem<String>( value: 'Friends',
value: 'Events', child: MenuItemWithIcon(Icons.people, 'Friends', '5 new'),
child: MenuItemWithIcon(Icons.event, 'Events', '12 upcoming'), ),
), const PopupMenuItem<String>(
const PopupMenuItem<String>( value: 'Events',
value: 'Events', child: MenuItemWithIcon(Icons.event, 'Events', '12 upcoming'),
child: MenuItemWithIcon(Icons.group, 'Groups', '14'), ),
), const PopupMenuItem<String>(
const PopupMenuItem<String>( value: 'Events',
value: 'Events', child: MenuItemWithIcon(Icons.group, 'Groups', '14'),
child: MenuItemWithIcon(Icons.image, 'Pictures', '12'), ),
), const PopupMenuItem<String>(
const PopupMenuItem<String>( value: 'Events',
value: 'Events', child: MenuItemWithIcon(Icons.image, 'Pictures', '12'),
child: MenuItemWithIcon(Icons.near_me, 'Nearby', '33'), ),
), const PopupMenuItem<String>(
const PopupMenuItem<String>( value: 'Events',
value: 'Friends', child: MenuItemWithIcon(Icons.near_me, 'Nearby', '33'),
child: MenuItemWithIcon(Icons.people, 'Friends', '5'), ),
), const PopupMenuItem<String>(
const PopupMenuItem<String>( value: 'Friends',
value: 'Events', child: MenuItemWithIcon(Icons.people, 'Friends', '5'),
child: MenuItemWithIcon(Icons.event, 'Events', '12'), ),
), const PopupMenuItem<String>(
const PopupMenuItem<String>( value: 'Events',
value: 'Events', child: MenuItemWithIcon(Icons.event, 'Events', '12'),
child: MenuItemWithIcon(Icons.group, 'Groups', '14'), ),
), const PopupMenuItem<String>(
const PopupMenuItem<String>( value: 'Events',
value: 'Events', child: MenuItemWithIcon(Icons.group, 'Groups', '14'),
child: MenuItemWithIcon(Icons.image, 'Pictures', '12'), ),
), const PopupMenuItem<String>(
const PopupMenuItem<String>( value: 'Events',
value: 'Events', child: MenuItemWithIcon(Icons.image, 'Pictures', '12'),
child: MenuItemWithIcon(Icons.near_me, 'Nearby', '33'), ),
), const PopupMenuItem<String>(
], value: 'Events',
child: MenuItemWithIcon(Icons.near_me, 'Nearby', '33'),
),
],
); );
} }
} }
@ -200,10 +201,7 @@ class MenuItemWithIcon extends StatelessWidget {
return Row( return Row(
children: <Widget>[ children: <Widget>[
Icon(icon), Icon(icon),
Padding( Padding(padding: const EdgeInsets.only(left: 8.0, right: 8.0), child: Text(title)),
padding: const EdgeInsets.only(left: 8.0, right: 8.0),
child: Text(title),
),
Text(subtitle, style: Theme.of(context).textTheme.bodySmall), Text(subtitle, style: Theme.of(context).textTheme.bodySmall),
], ],
); );
@ -223,10 +221,7 @@ class FancyImageItem extends StatelessWidget {
const ItemDescription(), const ItemDescription(),
const ItemImageBox(), const ItemImageBox(),
const InfoBar(), const InfoBar(),
const Padding( const Padding(padding: EdgeInsets.symmetric(horizontal: 8.0), child: Divider()),
padding: EdgeInsets.symmetric(horizontal: 8.0),
child: Divider(),
),
const IconBar(), const IconBar(),
const FatDivider(), const FatDivider(),
], ],
@ -245,10 +240,7 @@ class FancyGalleryItem extends StatelessWidget {
const UserHeader('Ali Connors'), const UserHeader('Ali Connors'),
ItemGalleryBox(index), ItemGalleryBox(index),
const InfoBar(), const InfoBar(),
const Padding( const Padding(padding: EdgeInsets.symmetric(horizontal: 8.0), child: Divider()),
padding: EdgeInsets.symmetric(horizontal: 8.0),
child: Divider(),
),
const IconBar(), const IconBar(),
const FatDivider(), const FatDivider(),
], ],
@ -306,7 +298,9 @@ class IconWithText extends StatelessWidget {
children: <Widget>[ children: <Widget>[
IconButton( IconButton(
icon: Icon(icon), icon: Icon(icon),
onPressed: () { print('Pressed $title button'); }, onPressed: () {
print('Pressed $title button');
},
), ),
Text(title), Text(title),
], ],
@ -348,10 +342,7 @@ class FatDivider extends StatelessWidget {
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
return Container( return Container(height: 8.0, color: Theme.of(context).dividerColor);
height: 8.0,
color: Theme.of(context).dividerColor,
);
} }
} }
@ -379,18 +370,24 @@ class UserHeader extends StatelessWidget {
child: Column( child: Column(
crossAxisAlignment: CrossAxisAlignment.stretch, crossAxisAlignment: CrossAxisAlignment.stretch,
children: <Widget>[ children: <Widget>[
RichText(text: TextSpan( RichText(
style: Theme.of(context).textTheme.bodyMedium, text: TextSpan(
children: <TextSpan>[ style: Theme.of(context).textTheme.bodyMedium,
TextSpan(text: userName, style: const TextStyle(fontWeight: FontWeight.bold)), children: <TextSpan>[
const TextSpan(text: ' shared a new '), TextSpan(text: userName, style: const TextStyle(fontWeight: FontWeight.bold)),
const TextSpan(text: 'photo', style: TextStyle(fontWeight: FontWeight.bold)), const TextSpan(text: ' shared a new '),
], const TextSpan(text: 'photo', style: TextStyle(fontWeight: FontWeight.bold)),
)), ],
),
),
Row( Row(
children: <Widget>[ children: <Widget>[
Text('Yesterday at 11:55 • ', style: Theme.of(context).textTheme.bodySmall), Text('Yesterday at 11:55 • ', style: Theme.of(context).textTheme.bodySmall),
Icon(Icons.people, size: 16.0, color: Theme.of(context).textTheme.bodySmall!.color), Icon(
Icons.people,
size: 16.0,
color: Theme.of(context).textTheme.bodySmall!.color,
),
], ],
), ),
], ],
@ -410,7 +407,9 @@ class ItemDescription extends StatelessWidget {
Widget build(BuildContext context) { Widget build(BuildContext context) {
return const Padding( return const Padding(
padding: EdgeInsets.all(8.0), padding: EdgeInsets.all(8.0),
child: Text('Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.'), child: Text(
'Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.',
),
); );
} }
} }
@ -431,7 +430,9 @@ class ItemImageBox extends StatelessWidget {
const SizedBox( const SizedBox(
height: 230.0, height: 230.0,
child: Image( child: Image(
image: AssetImage('packages/flutter_gallery_assets/places/india_chettinad_silk_maker.png') image: AssetImage(
'packages/flutter_gallery_assets/places/india_chettinad_silk_maker.png',
),
), ),
), ),
Theme( Theme(
@ -441,11 +442,15 @@ class ItemImageBox extends StatelessWidget {
children: <Widget>[ children: <Widget>[
IconButton( IconButton(
icon: const Icon(Icons.edit), icon: const Icon(Icons.edit),
onPressed: () { print('Pressed edit button'); }, onPressed: () {
print('Pressed edit button');
},
), ),
IconButton( IconButton(
icon: const Icon(Icons.zoom_in), icon: const Icon(Icons.zoom_in),
onPressed: () { print('Pressed zoom button'); }, onPressed: () {
print('Pressed zoom button');
},
), ),
], ],
), ),
@ -463,9 +468,7 @@ class ItemImageBox extends StatelessWidget {
text: const TextSpan( text: const TextSpan(
style: TextStyle(color: Colors.white), style: TextStyle(color: Colors.white),
children: <TextSpan>[ children: <TextSpan>[
TextSpan( TextSpan(text: 'Photo by '),
text: 'Photo by '
),
TextSpan( TextSpan(
style: TextStyle(fontWeight: FontWeight.bold), style: TextStyle(fontWeight: FontWeight.bold),
text: 'Chris Godley', text: 'Chris Godley',
@ -476,8 +479,7 @@ class ItemImageBox extends StatelessWidget {
), ),
), ),
], ],
) ),
,
Padding( Padding(
padding: const EdgeInsets.all(8.0), padding: const EdgeInsets.all(8.0),
child: Column( child: Column(
@ -503,9 +505,7 @@ class ItemGalleryBox extends StatelessWidget {
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
final List<String> tabNames = <String>[ final List<String> tabNames = <String>['A', 'B', 'C', 'D'];
'A', 'B', 'C', 'D',
];
return SizedBox( return SizedBox(
height: 200.0, height: 200.0,
@ -515,46 +515,56 @@ class ItemGalleryBox extends StatelessWidget {
children: <Widget>[ children: <Widget>[
Expanded( Expanded(
child: TabBarView( child: TabBarView(
children: tabNames.map<Widget>((String tabName) { children:
return Container( tabNames.map<Widget>((String tabName) {
key: PageStorageKey<String>(tabName), return Container(
child: Padding( key: PageStorageKey<String>(tabName),
padding: const EdgeInsets.all(8.0), child: Padding(
child: Card( padding: const EdgeInsets.all(8.0),
child: Column( child: Card(
children: <Widget>[ child: Column(
Expanded(
child: ColoredBox(
color: Theme.of(context).primaryColor,
child: Center(
child: Text(tabName, style: Theme.of(context).textTheme.headlineSmall!.copyWith(color: Colors.white)),
),
),
),
Row(
children: <Widget>[ children: <Widget>[
IconButton(
icon: const Icon(Icons.share),
onPressed: () { print('Pressed share'); },
),
IconButton(
icon: const Icon(Icons.event),
onPressed: () { print('Pressed event'); },
),
Expanded( Expanded(
child: Padding( child: ColoredBox(
padding: const EdgeInsets.only(left: 8.0), color: Theme.of(context).primaryColor,
child: Text('This is item $tabName'), child: Center(
child: Text(
tabName,
style: Theme.of(
context,
).textTheme.headlineSmall!.copyWith(color: Colors.white),
),
),
), ),
), ),
Row(
children: <Widget>[
IconButton(
icon: const Icon(Icons.share),
onPressed: () {
print('Pressed share');
},
),
IconButton(
icon: const Icon(Icons.event),
onPressed: () {
print('Pressed event');
},
),
Expanded(
child: Padding(
padding: const EdgeInsets.only(left: 8.0),
child: Text('This is item $tabName'),
),
),
],
),
], ],
), ),
], ),
), ),
), );
), }).toList(),
);
}).toList(),
), ),
), ),
const TabPageSelector(), const TabPageSelector(),
@ -572,11 +582,7 @@ class BottomBar extends StatelessWidget {
Widget build(BuildContext context) { Widget build(BuildContext context) {
return Container( return Container(
decoration: BoxDecoration( decoration: BoxDecoration(
border: Border( border: Border(top: BorderSide(color: Theme.of(context).dividerColor)),
top: BorderSide(
color: Theme.of(context).dividerColor,
),
),
), ),
child: const Row( child: const Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween, mainAxisAlignment: MainAxisAlignment.spaceBetween,
@ -606,7 +612,9 @@ class BottomBarButton extends StatelessWidget {
children: <Widget>[ children: <Widget>[
IconButton( IconButton(
icon: Icon(icon), icon: Icon(icon),
onPressed: () { print('Pressed: $title'); }, onPressed: () {
print('Pressed: $title');
},
), ),
Text(title, style: Theme.of(context).textTheme.bodySmall), Text(title, style: Theme.of(context).textTheme.bodySmall),
], ],
@ -616,7 +624,7 @@ class BottomBarButton extends StatelessWidget {
} }
class GalleryDrawer extends StatelessWidget { class GalleryDrawer extends StatelessWidget {
const GalleryDrawer({ super.key }); const GalleryDrawer({super.key});
void _changeTheme(BuildContext context, bool value) { void _changeTheme(BuildContext context, bool value) {
ComplexLayoutApp.of(context)?.lightTheme = value; ComplexLayoutApp.of(context)?.lightTheme = value;
@ -642,31 +650,42 @@ class GalleryDrawer extends StatelessWidget {
key: const Key('scroll-switcher'), key: const Key('scroll-switcher'),
title: const Text('Scroll Mode'), title: const Text('Scroll Mode'),
onTap: () { onTap: () {
_changeScrollMode(context, currentMode == ScrollMode.complex ? ScrollMode.tile : ScrollMode.complex); _changeScrollMode(
Navigator.pop(context); context,
currentMode == ScrollMode.complex ? ScrollMode.tile : ScrollMode.complex,
);
Navigator.pop(context);
}, },
trailing: Text(currentMode == ScrollMode.complex ? 'Tile' : 'Complex'), trailing: Text(currentMode == ScrollMode.complex ? 'Tile' : 'Complex'),
), ),
ListTile( ListTile(
leading: const Icon(Icons.brightness_5), leading: const Icon(Icons.brightness_5),
title: const Text('Light'), title: const Text('Light'),
onTap: () { _changeTheme(context, true); }, onTap: () {
_changeTheme(context, true);
},
selected: ComplexLayoutApp.of(context)!.lightTheme, selected: ComplexLayoutApp.of(context)!.lightTheme,
trailing: Radio<bool>( trailing: Radio<bool>(
value: true, value: true,
groupValue: ComplexLayoutApp.of(context)!.lightTheme, groupValue: ComplexLayoutApp.of(context)!.lightTheme,
onChanged: (bool? value) { _changeTheme(context, value!); }, onChanged: (bool? value) {
_changeTheme(context, value!);
},
), ),
), ),
ListTile( ListTile(
leading: const Icon(Icons.brightness_7), leading: const Icon(Icons.brightness_7),
title: const Text('Dark'), title: const Text('Dark'),
onTap: () { _changeTheme(context, false); }, onTap: () {
_changeTheme(context, false);
},
selected: !ComplexLayoutApp.of(context)!.lightTheme, selected: !ComplexLayoutApp.of(context)!.lightTheme,
trailing: Radio<bool>( trailing: Radio<bool>(
value: false, value: false,
groupValue: ComplexLayoutApp.of(context)!.lightTheme, groupValue: ComplexLayoutApp.of(context)!.lightTheme,
onChanged: (bool? value) { _changeTheme(context, value!); }, onChanged: (bool? value) {
_changeTheme(context, value!);
},
), ),
), ),
const Divider(), const Divider(),
@ -674,10 +693,14 @@ class GalleryDrawer extends StatelessWidget {
leading: const Icon(Icons.hourglass_empty), leading: const Icon(Icons.hourglass_empty),
title: const Text('Animate Slowly'), title: const Text('Animate Slowly'),
selected: timeDilation != 1.0, selected: timeDilation != 1.0,
onTap: () { ComplexLayoutApp.of(context)!.toggleAnimationSpeed(); }, onTap: () {
ComplexLayoutApp.of(context)!.toggleAnimationSpeed();
},
trailing: Checkbox( trailing: Checkbox(
value: timeDilation != 1.0, value: timeDilation != 1.0,
onChanged: (bool? value) { ComplexLayoutApp.of(context)!.toggleAnimationSpeed(); }, onChanged: (bool? value) {
ComplexLayoutApp.of(context)!.toggleAnimationSpeed();
},
), ),
), ),
], ],
@ -694,10 +717,7 @@ class FancyDrawerHeader extends StatelessWidget {
return Container( return Container(
color: Colors.purple, color: Colors.purple,
height: 200.0, height: 200.0,
child: const SafeArea( child: const SafeArea(bottom: false, child: Placeholder()),
bottom: false,
child: Placeholder(),
),
); );
} }
} }

View File

@ -24,17 +24,11 @@ Iterable<PointerEvent> dragInputEvents(
final Offset startLocation = center - totalMove / 2; final Offset startLocation = center - totalMove / 2;
// The issue is about 120Hz input on 90Hz refresh rate device. // The issue is about 120Hz input on 90Hz refresh rate device.
// We test 90Hz input on 60Hz device here, which shows similar pattern. // We test 90Hz input on 60Hz device here, which shows similar pattern.
final int moveEventCount = totalTime.inMicroseconds * frequency ~/ const Duration(seconds: 1).inMicroseconds; final int moveEventCount =
totalTime.inMicroseconds * frequency ~/ const Duration(seconds: 1).inMicroseconds;
final Offset movePerEvent = totalMove / moveEventCount.toDouble(); final Offset movePerEvent = totalMove / moveEventCount.toDouble();
yield PointerAddedEvent( yield PointerAddedEvent(timeStamp: epoch, position: startLocation);
timeStamp: epoch, yield PointerDownEvent(timeStamp: epoch, position: startLocation, pointer: 1);
position: startLocation,
);
yield PointerDownEvent(
timeStamp: epoch,
position: startLocation,
pointer: 1,
);
for (int t = 0; t < moveEventCount + 1; t++) { for (int t = 0; t < moveEventCount + 1; t++) {
final Offset position = startLocation + movePerEvent * t.toDouble(); final Offset position = startLocation + movePerEvent * t.toDouble();
yield PointerMoveEvent( yield PointerMoveEvent(
@ -45,19 +39,10 @@ Iterable<PointerEvent> dragInputEvents(
); );
} }
final Offset position = startLocation + totalMove; final Offset position = startLocation + totalMove;
yield PointerUpEvent( yield PointerUpEvent(timeStamp: epoch + totalTime, position: position, pointer: 1);
timeStamp: epoch + totalTime,
position: position,
pointer: 1,
);
} }
enum TestScenario { enum TestScenario { resampleOn90Hz, resampleOn59Hz, resampleOff90Hz, resampleOff59Hz }
resampleOn90Hz,
resampleOn59Hz,
resampleOff90Hz,
resampleOff59Hz,
}
class ResampleFlagVariant extends TestVariant<TestScenario> { class ResampleFlagVariant extends TestVariant<TestScenario> {
ResampleFlagVariant(this.binding); ResampleFlagVariant(this.binding);
@ -69,7 +54,7 @@ class ResampleFlagVariant extends TestVariant<TestScenario> {
late TestScenario currentValue; late TestScenario currentValue;
bool get resample => switch (currentValue) { bool get resample => switch (currentValue) {
TestScenario.resampleOn90Hz || TestScenario.resampleOn59Hz => true, TestScenario.resampleOn90Hz || TestScenario.resampleOn59Hz => true,
TestScenario.resampleOff90Hz || TestScenario.resampleOff59Hz => false, TestScenario.resampleOff90Hz || TestScenario.resampleOff59Hz => false,
}; };
@ -83,8 +68,8 @@ class ResampleFlagVariant extends TestVariant<TestScenario> {
@override @override
String describeValue(TestScenario value) { String describeValue(TestScenario value) {
return switch (value) { return switch (value) {
TestScenario.resampleOn90Hz => 'resample on with 90Hz input', TestScenario.resampleOn90Hz => 'resample on with 90Hz input',
TestScenario.resampleOn59Hz => 'resample on with 59Hz input', TestScenario.resampleOn59Hz => 'resample on with 59Hz input',
TestScenario.resampleOff90Hz => 'resample off with 90Hz input', TestScenario.resampleOff90Hz => 'resample off with 90Hz input',
TestScenario.resampleOff59Hz => 'resample off with 59Hz input', TestScenario.resampleOff59Hz => 'resample off with 59Hz input',
}; };
@ -108,61 +93,67 @@ class ResampleFlagVariant extends TestVariant<TestScenario> {
Future<void> main() async { Future<void> main() async {
final WidgetsBinding widgetsBinding = IntegrationTestWidgetsFlutterBinding.ensureInitialized(); final WidgetsBinding widgetsBinding = IntegrationTestWidgetsFlutterBinding.ensureInitialized();
assert(widgetsBinding is IntegrationTestWidgetsFlutterBinding); assert(widgetsBinding is IntegrationTestWidgetsFlutterBinding);
final IntegrationTestWidgetsFlutterBinding binding = widgetsBinding as IntegrationTestWidgetsFlutterBinding; final IntegrationTestWidgetsFlutterBinding binding =
widgetsBinding as IntegrationTestWidgetsFlutterBinding;
binding.framePolicy = LiveTestWidgetsFlutterBindingFramePolicy.benchmarkLive; binding.framePolicy = LiveTestWidgetsFlutterBindingFramePolicy.benchmarkLive;
binding.reportData ??= <String, dynamic>{}; binding.reportData ??= <String, dynamic>{};
final ResampleFlagVariant variant = ResampleFlagVariant(binding); final ResampleFlagVariant variant = ResampleFlagVariant(binding);
testWidgets('Smoothness test', (WidgetTester tester) async { testWidgets(
app.main(); 'Smoothness test',
await tester.pumpAndSettle(); (WidgetTester tester) async {
final Finder scrollerFinder = find.byKey(const ValueKey<String>('complex-scroll')); app.main();
final ListView scroller = tester.widget<ListView>(scrollerFinder); await tester.pumpAndSettle();
final ScrollController? controller = scroller.controller; final Finder scrollerFinder = find.byKey(const ValueKey<String>('complex-scroll'));
final List<int> frameTimestamp = <int>[]; final ListView scroller = tester.widget<ListView>(scrollerFinder);
final List<double> scrollOffset = <double>[]; final ScrollController? controller = scroller.controller;
final List<Duration> delays = <Duration>[]; final List<int> frameTimestamp = <int>[];
binding.addPersistentFrameCallback((Duration timeStamp) { final List<double> scrollOffset = <double>[];
if (controller?.hasClients ?? false) { final List<Duration> delays = <Duration>[];
// This if is necessary because by the end of the test the widget tree binding.addPersistentFrameCallback((Duration timeStamp) {
// is destroyed. if (controller?.hasClients ?? false) {
frameTimestamp.add(timeStamp.inMicroseconds); // This if is necessary because by the end of the test the widget tree
scrollOffset.add(controller!.offset); // is destroyed.
} frameTimestamp.add(timeStamp.inMicroseconds);
}); scrollOffset.add(controller!.offset);
Duration now() => binding.currentSystemFrameTimeStamp;
Future<void> scroll() async {
// Extra 50ms to avoid timeouts.
final Duration startTime = const Duration(milliseconds: 500) + now();
for (final PointerEvent event in dragInputEvents(
startTime,
tester.getCenter(scrollerFinder),
frequency: variant.frequency,
)) {
await tester.binding.delayed(event.timeStamp - now());
// This now measures how accurate the above delayed is.
final Duration delay = now() - event.timeStamp;
if (delays.length < frameTimestamp.length) {
while (delays.length < frameTimestamp.length - 1) {
delays.add(Duration.zero);
}
delays.add(delay);
} else if (delays.last < delay) {
delays.last = delay;
} }
tester.binding.handlePointerEventForSource(event, source: TestBindingEventSource.test); });
}
}
for (int n = 0; n < 5; n++) { Duration now() => binding.currentSystemFrameTimeStamp;
await scroll(); Future<void> scroll() async {
} // Extra 50ms to avoid timeouts.
variant.result = scrollSummary(scrollOffset, delays, frameTimestamp); final Duration startTime = const Duration(milliseconds: 500) + now();
await tester.pumpAndSettle(); for (final PointerEvent event in dragInputEvents(
scrollOffset.clear(); startTime,
delays.clear(); tester.getCenter(scrollerFinder),
await tester.idle(); frequency: variant.frequency,
}, semanticsEnabled: false, variant: variant); )) {
await tester.binding.delayed(event.timeStamp - now());
// This now measures how accurate the above delayed is.
final Duration delay = now() - event.timeStamp;
if (delays.length < frameTimestamp.length) {
while (delays.length < frameTimestamp.length - 1) {
delays.add(Duration.zero);
}
delays.add(delay);
} else if (delays.last < delay) {
delays.last = delay;
}
tester.binding.handlePointerEventForSource(event, source: TestBindingEventSource.test);
}
}
for (int n = 0; n < 5; n++) {
await scroll();
}
variant.result = scrollSummary(scrollOffset, delays, frameTimestamp);
await tester.pumpAndSettle();
scrollOffset.clear();
delays.clear();
await tester.idle();
},
semanticsEnabled: false,
variant: variant,
);
} }
/// Calculates the smoothness measure from `scrollOffset` and `delays` list. /// Calculates the smoothness measure from `scrollOffset` and `delays` list.
@ -215,15 +206,15 @@ Map<String, dynamic> scrollSummary(
double jankyCount = 0; double jankyCount = 0;
double absJerkAvg = 0; double absJerkAvg = 0;
int lostFrame = 0; int lostFrame = 0;
for (int i = 1; i < scrollOffset.length-1; i += 1) { for (int i = 1; i < scrollOffset.length - 1; i += 1) {
if (frameTimestamp[i+1] - frameTimestamp[i-1] > 40E3 || if (frameTimestamp[i + 1] - frameTimestamp[i - 1] > 40E3 ||
(i >= delays.length || delays[i] > const Duration(milliseconds: 16))) { (i >= delays.length || delays[i] > const Duration(milliseconds: 16))) {
// filter data points from slow frame building or input simulation artifact // filter data points from slow frame building or input simulation artifact
lostFrame += 1; lostFrame += 1;
continue; continue;
} }
// //
final double absJerk = (scrollOffset[i-1] + scrollOffset[i+1] - 2*scrollOffset[i]).abs(); final double absJerk = (scrollOffset[i - 1] + scrollOffset[i + 1] - 2 * scrollOffset[i]).abs();
absJerkAvg += absJerk; absJerkAvg += absJerk;
if (absJerk > 0.5) { if (absJerk > 0.5) {
jankyCount += 1; jankyCount += 1;

View File

@ -8,9 +8,6 @@ import 'package:integration_test/integration_test_driver.dart' as driver;
Future<void> main() => driver.integrationDriver( Future<void> main() => driver.integrationDriver(
responseDataCallback: (Map<String, dynamic>? data) async { responseDataCallback: (Map<String, dynamic>? data) async {
await driver.writeResponseData( await driver.writeResponseData(data, testOutputFilename: 'scroll_smoothness_test');
data, },
testOutputFilename: 'scroll_smoothness_test',
);
}
); );

View File

@ -47,26 +47,39 @@ void main() {
expect( expect(
await driver.setSemantics(true), await driver.setSemantics(true),
isTrue, isTrue,
reason: 'Could not toggle semantics to on because semantics were already ' reason:
'on, but the test needs to toggle semantics to measure the initial ' 'Could not toggle semantics to on because semantics were already '
'semantics tree generation in isolation.' 'on, but the test needs to toggle semantics to measure the initial '
'semantics tree generation in isolation.',
); );
}); });
final Iterable<TimelineEvent>? semanticsEvents = timeline.events?.where((TimelineEvent event) => event.name == 'SEMANTICS'); final Iterable<TimelineEvent>? semanticsEvents = timeline.events?.where(
(TimelineEvent event) => event.name == 'SEMANTICS',
);
if (semanticsEvents?.length != 2) { if (semanticsEvents?.length != 2) {
fail('Expected exactly two "SEMANTICS" events, got ${semanticsEvents?.length}:\n$semanticsEvents'); fail(
'Expected exactly two "SEMANTICS" events, got ${semanticsEvents?.length}:\n$semanticsEvents',
);
} }
final Duration semanticsTreeCreation = Duration(microseconds: semanticsEvents!.last.timestampMicros! - semanticsEvents.first.timestampMicros!); final Duration semanticsTreeCreation = Duration(
microseconds:
semanticsEvents!.last.timestampMicros! - semanticsEvents.first.timestampMicros!,
);
final String jsonEncoded = json.encode(<String, dynamic>{'initialSemanticsTreeCreation': semanticsTreeCreation.inMilliseconds}); final String jsonEncoded = json.encode(<String, dynamic>{
File(p.join(testOutputsDirectory, 'complex_layout_semantics_perf.json')).writeAsStringSync(jsonEncoded); 'initialSemanticsTreeCreation': semanticsTreeCreation.inMilliseconds,
});
File(
p.join(testOutputsDirectory, 'complex_layout_semantics_perf.json'),
).writeAsStringSync(jsonEncoded);
}, timeout: Timeout.none); }, timeout: Timeout.none);
}); });
} }
String _adbPath() { String _adbPath() {
final String? androidHome = Platform.environment['ANDROID_HOME'] ?? Platform.environment['ANDROID_SDK_ROOT']; final String? androidHome =
Platform.environment['ANDROID_HOME'] ?? Platform.environment['ANDROID_SDK_ROOT'];
if (androidHome == null) { if (androidHome == null) {
return 'adb'; return 'adb';
} else { } else {

View File

@ -21,16 +21,16 @@ const Duration pauses = Duration(milliseconds: 500);
Future<void> main() async { Future<void> main() async {
final Completer<void> ready = Completer<void>(); final Completer<void> ready = Completer<void>();
runApp(GestureDetector( runApp(
onTap: () { GestureDetector(
debugPrint('==== MEMORY BENCHMARK ==== TAPPED ===='); onTap: () {
ready.complete(); debugPrint('==== MEMORY BENCHMARK ==== TAPPED ====');
}, ready.complete();
behavior: HitTestBehavior.opaque, },
child: const IgnorePointer( behavior: HitTestBehavior.opaque,
child: ComplexLayoutApp(), child: const IgnorePointer(child: ComplexLayoutApp()),
), ),
)); );
await SchedulerBinding.instance.endOfFrame; await SchedulerBinding.instance.endOfFrame;
debugPrint('==== MEMORY BENCHMARK ==== READY ===='); debugPrint('==== MEMORY BENCHMARK ==== READY ====');
@ -41,12 +41,7 @@ Future<void> main() async {
await Future<void>.delayed(const Duration(milliseconds: 200)); await Future<void>.delayed(const Duration(milliseconds: 200));
// remove onTap handler, enable pointer events for app // remove onTap handler, enable pointer events for app
runApp(GestureDetector( runApp(GestureDetector(child: const IgnorePointer(ignoring: false, child: ComplexLayoutApp())));
child: const IgnorePointer(
ignoring: false,
child: ComplexLayoutApp(),
),
));
await SchedulerBinding.instance.endOfFrame; await SchedulerBinding.instance.endOfFrame;
final WidgetController controller = LiveWidgetController(WidgetsBinding.instance); final WidgetController controller = LiveWidgetController(WidgetsBinding.instance);

View File

@ -43,19 +43,28 @@ const String kAnimatedAdvancedBlend = '/animated_advanced_blend';
const String kRRectBlurRouteName = '/rrect_blur'; const String kRRectBlurRouteName = '/rrect_blur';
const String kOpacityPeepholeOneRectRouteName = '$kOpacityPeepholeRouteName/one_big_rect'; const String kOpacityPeepholeOneRectRouteName = '$kOpacityPeepholeRouteName/one_big_rect';
const String kOpacityPeepholeColumnOfOpacityRouteName = '$kOpacityPeepholeRouteName/column_of_opacity'; const String kOpacityPeepholeColumnOfOpacityRouteName =
const String kOpacityPeepholeOpacityOfCachedChildRouteName = '$kOpacityPeepholeRouteName/opacity_of_cached_child'; '$kOpacityPeepholeRouteName/column_of_opacity';
const String kOpacityPeepholeOpacityOfColumnRouteName = '$kOpacityPeepholeRouteName/opacity_of_column'; const String kOpacityPeepholeOpacityOfCachedChildRouteName =
'$kOpacityPeepholeRouteName/opacity_of_cached_child';
const String kOpacityPeepholeOpacityOfColumnRouteName =
'$kOpacityPeepholeRouteName/opacity_of_column';
const String kOpacityPeepholeGridOfOpacityRouteName = '$kOpacityPeepholeRouteName/grid_of_opacity'; const String kOpacityPeepholeGridOfOpacityRouteName = '$kOpacityPeepholeRouteName/grid_of_opacity';
const String kOpacityPeepholeOpacityOfGridRouteName = '$kOpacityPeepholeRouteName/opacity_of_grid'; const String kOpacityPeepholeOpacityOfGridRouteName = '$kOpacityPeepholeRouteName/opacity_of_grid';
const String kOpacityPeepholeOpacityOfColOfRowsRouteName = '$kOpacityPeepholeRouteName/opacity_of_col_of_rows'; const String kOpacityPeepholeOpacityOfColOfRowsRouteName =
const String kOpacityPeepholeFadeTransitionTextRouteName = '$kOpacityPeepholeRouteName/fade_transition_text'; '$kOpacityPeepholeRouteName/opacity_of_col_of_rows';
const String kOpacityPeepholeGridOfRectsWithAlphaRouteName = '$kOpacityPeepholeRouteName/grid_of_rects_with_alpha'; const String kOpacityPeepholeFadeTransitionTextRouteName =
const String kOpacityPeepholeGridOfAlphaSaveLayerRectsRouteName = '$kOpacityPeepholeRouteName/grid_of_alpha_savelayer_rects'; '$kOpacityPeepholeRouteName/fade_transition_text';
const String kOpacityPeepholeColumnOfAlphaSaveLayerRowsOfRectsRouteName = '$kOpacityPeepholeRouteName/column_of_alpha_save_layer_rows_of_rects'; const String kOpacityPeepholeGridOfRectsWithAlphaRouteName =
'$kOpacityPeepholeRouteName/grid_of_rects_with_alpha';
const String kOpacityPeepholeGridOfAlphaSaveLayerRectsRouteName =
'$kOpacityPeepholeRouteName/grid_of_alpha_savelayer_rects';
const String kOpacityPeepholeColumnOfAlphaSaveLayerRowsOfRectsRouteName =
'$kOpacityPeepholeRouteName/column_of_alpha_save_layer_rows_of_rects';
const String kGradientPerfRecreateDynamicRouteName = '$kGradientPerfRouteName/recreate_dynamic'; const String kGradientPerfRecreateDynamicRouteName = '$kGradientPerfRouteName/recreate_dynamic';
const String kGradientPerfRecreateConsistentRouteName = '$kGradientPerfRouteName/recreate_consistent'; const String kGradientPerfRecreateConsistentRouteName =
'$kGradientPerfRouteName/recreate_consistent';
const String kGradientPerfStaticConsistentRouteName = '$kGradientPerfRouteName/static_consistent'; const String kGradientPerfStaticConsistentRouteName = '$kGradientPerfRouteName/static_consistent';
const String kScrollableName = '/macrobenchmark_listview'; const String kScrollableName = '/macrobenchmark_listview';

View File

@ -64,7 +64,8 @@ class MacrobenchmarksApp extends StatelessWidget {
kPostBackdropFilterRouteName: (BuildContext context) => const PostBackdropFilterPage(), kPostBackdropFilterRouteName: (BuildContext context) => const PostBackdropFilterPage(),
kSimpleAnimationRouteName: (BuildContext context) => const SimpleAnimationPage(), kSimpleAnimationRouteName: (BuildContext context) => const SimpleAnimationPage(),
kPictureCacheRouteName: (BuildContext context) => const PictureCachePage(), kPictureCacheRouteName: (BuildContext context) => const PictureCachePage(),
kPictureCacheComplexityScoringRouteName: (BuildContext context) => const PictureCacheComplexityScoringPage(), kPictureCacheComplexityScoringRouteName:
(BuildContext context) => const PictureCacheComplexityScoringPage(),
kLargeImageChangerRouteName: (BuildContext context) => const LargeImageChangerPage(), kLargeImageChangerRouteName: (BuildContext context) => const LargeImageChangerPage(),
kLargeImagesRouteName: (BuildContext context) => const LargeImagesPage(), kLargeImagesRouteName: (BuildContext context) => const LargeImagesPage(),
kTextRouteName: (BuildContext context) => const TextPage(), kTextRouteName: (BuildContext context) => const TextPage(),
@ -74,23 +75,30 @@ class MacrobenchmarksApp extends StatelessWidget {
kClipperCacheRouteName: (BuildContext context) => const ClipperCachePage(), kClipperCacheRouteName: (BuildContext context) => const ClipperCachePage(),
kColorFilterAndFadeRouteName: (BuildContext context) => const ColorFilterAndFadePage(), kColorFilterAndFadeRouteName: (BuildContext context) => const ColorFilterAndFadePage(),
kColorFilterCacheRouteName: (BuildContext context) => const ColorFilterCachePage(), kColorFilterCacheRouteName: (BuildContext context) => const ColorFilterCachePage(),
kColorFilterWithUnstableChildName: (BuildContext context) => const ColorFilterWithUnstableChildPage(), kColorFilterWithUnstableChildName:
kFadingChildAnimationRouteName: (BuildContext context) => const FilteredChildAnimationPage(FilterType.opacity), (BuildContext context) => const ColorFilterWithUnstableChildPage(),
kImageFilteredTransformAnimationRouteName: (BuildContext context) => const FilteredChildAnimationPage(FilterType.rotateFilter), kFadingChildAnimationRouteName:
kMultiWidgetConstructionRouteName: (BuildContext context) => const MultiWidgetConstructTable(10, 20), (BuildContext context) => const FilteredChildAnimationPage(FilterType.opacity),
kImageFilteredTransformAnimationRouteName:
(BuildContext context) => const FilteredChildAnimationPage(FilterType.rotateFilter),
kMultiWidgetConstructionRouteName:
(BuildContext context) => const MultiWidgetConstructTable(10, 20),
kHeavyGridViewRouteName: (BuildContext context) => const HeavyGridViewPage(), kHeavyGridViewRouteName: (BuildContext context) => const HeavyGridViewPage(),
kRasterCacheUseMemory: (BuildContext context) => const RasterCacheUseMemory(), kRasterCacheUseMemory: (BuildContext context) => const RasterCacheUseMemory(),
kShaderMaskCacheRouteName: (BuildContext context) => const ShaderMaskCachePage(), kShaderMaskCacheRouteName: (BuildContext context) => const ShaderMaskCachePage(),
kSimpleScrollRouteName: (BuildContext context) => const SimpleScroll(), kSimpleScrollRouteName: (BuildContext context) => const SimpleScroll(),
kAnimationWithMicrotasksRouteName: (BuildContext context) => const AnimationWithMicrotasks(), kAnimationWithMicrotasksRouteName:
(BuildContext context) => const AnimationWithMicrotasks(),
kAnimatedImageRouteName: (BuildContext context) => const AnimatedImagePage(), kAnimatedImageRouteName: (BuildContext context) => const AnimatedImagePage(),
kOpacityPeepholeRouteName: (BuildContext context) => const OpacityPeepholePage(), kOpacityPeepholeRouteName: (BuildContext context) => const OpacityPeepholePage(),
...opacityPeepholeRoutes, ...opacityPeepholeRoutes,
kGradientPerfRouteName: (BuildContext context) => const GradientPerfHomePage(), kGradientPerfRouteName: (BuildContext context) => const GradientPerfHomePage(),
...gradientPerfRoutes, ...gradientPerfRoutes,
kAnimatedComplexOpacityPerfRouteName: (BuildContext context) => const AnimatedComplexOpacity(), kAnimatedComplexOpacityPerfRouteName:
(BuildContext context) => const AnimatedComplexOpacity(),
kListTextLayoutRouteName: (BuildContext context) => const ColumnOfText(), kListTextLayoutRouteName: (BuildContext context) => const ColumnOfText(),
kAnimatedComplexImageFilteredPerfRouteName: (BuildContext context) => const AnimatedComplexImageFiltered(), kAnimatedComplexImageFilteredPerfRouteName:
(BuildContext context) => const AnimatedComplexImageFiltered(),
kAnimatedBlurBackdropFilter: (BuildContext context) => const AnimatedBlurBackdropFilter(), kAnimatedBlurBackdropFilter: (BuildContext context) => const AnimatedBlurBackdropFilter(),
kSlidersRouteName: (BuildContext context) => const SlidersPage(), kSlidersRouteName: (BuildContext context) => const SlidersPage(),
kDrawPointsPageRougeName: (BuildContext context) => const DrawPointsPage(), kDrawPointsPageRougeName: (BuildContext context) => const DrawPointsPage(),
@ -98,7 +106,8 @@ class MacrobenchmarksApp extends StatelessWidget {
kDrawAtlasPageRouteName: (BuildContext context) => const DrawAtlasPage(), kDrawAtlasPageRouteName: (BuildContext context) => const DrawAtlasPage(),
kAnimatedAdvancedBlend: (BuildContext context) => const AnimatedAdvancedBlend(), kAnimatedAdvancedBlend: (BuildContext context) => const AnimatedAdvancedBlend(),
kRRectBlurRouteName: (BuildContext context) => const RRectBlur(), kRRectBlurRouteName: (BuildContext context) => const RRectBlur(),
kVeryLongPictureScrollingRouteName: (BuildContext context) => const VeryLongPictureScrollingPerf(), kVeryLongPictureScrollingRouteName:
(BuildContext context) => const VeryLongPictureScrollingPerf(),
}, },
); );
} }

View File

@ -19,17 +19,20 @@ class _MultiplyPainter extends CustomPainter {
for (int y = 0; y < yDenominator; y++) { for (int y = 0; y < yDenominator; y++) {
for (int x = 0; x < xDenominator; x++) { for (int x = 0; x < xDenominator; x++) {
final Rect rect = Offset(x * width, y * height) & Size(width, height); final Rect rect = Offset(x * width, y * height) & Size(width, height);
final Paint basePaint = Paint() final Paint basePaint =
..color = Color.fromARGB( Paint()
(((x + 1) * width) / size.width * 255.0).floor(), ..color = Color.fromARGB(
(((y + 1) * height) / size.height * 255.0).floor(), (((x + 1) * width) / size.width * 255.0).floor(),
255, (((y + 1) * height) / size.height * 255.0).floor(),
127); 255,
127,
);
canvas.drawRect(rect, basePaint); canvas.drawRect(rect, basePaint);
final Paint multiplyPaint = Paint() final Paint multiplyPaint =
..color = _color Paint()
..blendMode = BlendMode.multiply; ..color = _color
..blendMode = BlendMode.multiply;
canvas.drawRect(rect, multiplyPaint); canvas.drawRect(rect, multiplyPaint);
} }
} }
@ -48,8 +51,12 @@ class AnimatedAdvancedBlend extends StatefulWidget {
State<AnimatedAdvancedBlend> createState() => _AnimatedAdvancedBlendState(); State<AnimatedAdvancedBlend> createState() => _AnimatedAdvancedBlendState();
} }
class _AnimatedAdvancedBlendState extends State<AnimatedAdvancedBlend> with SingleTickerProviderStateMixin { class _AnimatedAdvancedBlendState extends State<AnimatedAdvancedBlend>
late final AnimationController controller = AnimationController(vsync: this, duration: const Duration(milliseconds: 5000)); with SingleTickerProviderStateMixin {
late final AnimationController controller = AnimationController(
vsync: this,
duration: const Duration(milliseconds: 5000),
);
late final Animation<double> animation = controller.drive(Tween<double>(begin: 0.0, end: 1.0)); late final Animation<double> animation = controller.drive(Tween<double>(begin: 0.0, end: 1.0));
Color _color = const Color.fromARGB(255, 255, 0, 255); Color _color = const Color.fromARGB(255, 255, 0, 255);
@ -73,11 +80,7 @@ class _AnimatedAdvancedBlendState extends State<AnimatedAdvancedBlend> with Sing
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
return MaterialApp( return MaterialApp(
home: Scaffold( home: Scaffold(body: CustomPaint(painter: _MultiplyPainter(_color), child: Container())),
body: CustomPaint( );
painter: _MultiplyPainter(_color),
child: Container(),
),
));
} }
} }

View File

@ -9,14 +9,18 @@ import 'package:flutter/material.dart';
// dirty children even without explicit repaint boundaries. These intentionally use // dirty children even without explicit repaint boundaries. These intentionally use
// text to ensure we don't measure the opacity peephole case. // text to ensure we don't measure the opacity peephole case.
class AnimatedBlurBackdropFilter extends StatefulWidget { class AnimatedBlurBackdropFilter extends StatefulWidget {
const AnimatedBlurBackdropFilter({ super.key }); const AnimatedBlurBackdropFilter({super.key});
@override @override
State<AnimatedBlurBackdropFilter> createState() => _AnimatedBlurBackdropFilterState(); State<AnimatedBlurBackdropFilter> createState() => _AnimatedBlurBackdropFilterState();
} }
class _AnimatedBlurBackdropFilterState extends State<AnimatedBlurBackdropFilter> with SingleTickerProviderStateMixin { class _AnimatedBlurBackdropFilterState extends State<AnimatedBlurBackdropFilter>
late final AnimationController controller = AnimationController(vsync: this, duration: const Duration(milliseconds: 5000)); with SingleTickerProviderStateMixin {
late final AnimationController controller = AnimationController(
vsync: this,
duration: const Duration(milliseconds: 5000),
);
late final Animation<double> animation = controller.drive(Tween<double>(begin: 0.0, end: 1.0)); late final Animation<double> animation = controller.drive(Tween<double>(begin: 0.0, end: 1.0));
ui.ImageFilter imageFilter = ui.ImageFilter.blur(); ui.ImageFilter imageFilter = ui.ImageFilter.blur();
@ -55,10 +59,7 @@ class _AnimatedBlurBackdropFilterState extends State<AnimatedBlurBackdropFilter>
), ),
], ],
), ),
BackdropFilter( BackdropFilter(filter: imageFilter, child: const SizedBox.expand()),
filter: imageFilter,
child: const SizedBox.expand(),
),
], ],
), ),
), ),
@ -67,7 +68,7 @@ class _AnimatedBlurBackdropFilterState extends State<AnimatedBlurBackdropFilter>
} }
class ModeratelyComplexWidget extends StatelessWidget { class ModeratelyComplexWidget extends StatelessWidget {
const ModeratelyComplexWidget({ super.key }); const ModeratelyComplexWidget({super.key});
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
@ -76,7 +77,10 @@ class ModeratelyComplexWidget extends StatelessWidget {
clipBehavior: Clip.hardEdge, clipBehavior: Clip.hardEdge,
child: ListTile( child: ListTile(
leading: Icon(Icons.abc, size: 24), leading: Icon(Icons.abc, size: 24),
title: DecoratedBox(decoration: BoxDecoration(color: Colors.red), child: Text('Hello World')), title: DecoratedBox(
decoration: BoxDecoration(color: Colors.red),
child: Text('Hello World'),
),
trailing: FlutterLogo(), trailing: FlutterLogo(),
), ),
); );

View File

@ -9,14 +9,18 @@ import 'package:flutter/material.dart';
// dirty children even without explicit repaint boundaries. These intentionally use // dirty children even without explicit repaint boundaries. These intentionally use
// text to ensure we don't measure the opacity peephole case. // text to ensure we don't measure the opacity peephole case.
class AnimatedComplexImageFiltered extends StatefulWidget { class AnimatedComplexImageFiltered extends StatefulWidget {
const AnimatedComplexImageFiltered({ super.key }); const AnimatedComplexImageFiltered({super.key});
@override @override
State<AnimatedComplexImageFiltered> createState() => _AnimatedComplexImageFilteredState(); State<AnimatedComplexImageFiltered> createState() => _AnimatedComplexImageFilteredState();
} }
class _AnimatedComplexImageFilteredState extends State<AnimatedComplexImageFiltered> with SingleTickerProviderStateMixin { class _AnimatedComplexImageFilteredState extends State<AnimatedComplexImageFiltered>
late final AnimationController controller = AnimationController(vsync: this, duration: const Duration(milliseconds: 5000)); with SingleTickerProviderStateMixin {
late final AnimationController controller = AnimationController(
vsync: this,
duration: const Duration(milliseconds: 5000),
);
late final Animation<double> animation = controller.drive(Tween<double>(begin: 0.0, end: 1.0)); late final Animation<double> animation = controller.drive(Tween<double>(begin: 0.0, end: 1.0));
ui.ImageFilter imageFilter = ui.ImageFilter.blur(); ui.ImageFilter imageFilter = ui.ImageFilter.blur();
@ -44,12 +48,12 @@ class _AnimatedComplexImageFilteredState extends State<AnimatedComplexImageFilte
body: ListView( body: ListView(
children: <Widget>[ children: <Widget>[
for (int i = 0; i < 20; i++) for (int i = 0; i < 20; i++)
ImageFiltered( ImageFiltered(
imageFilter: imageFilter, imageFilter: imageFilter,
child: Center( child: Center(
child: Transform.scale(scale: 1.01, child: const ModeratelyComplexWidget()), child: Transform.scale(scale: 1.01, child: const ModeratelyComplexWidget()),
),
), ),
),
], ],
), ),
), ),
@ -58,7 +62,7 @@ class _AnimatedComplexImageFilteredState extends State<AnimatedComplexImageFilte
} }
class ModeratelyComplexWidget extends StatelessWidget { class ModeratelyComplexWidget extends StatelessWidget {
const ModeratelyComplexWidget({ super.key }); const ModeratelyComplexWidget({super.key});
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
@ -67,7 +71,10 @@ class ModeratelyComplexWidget extends StatelessWidget {
clipBehavior: Clip.hardEdge, clipBehavior: Clip.hardEdge,
child: ListTile( child: ListTile(
leading: Icon(Icons.abc, size: 24), leading: Icon(Icons.abc, size: 24),
title: DecoratedBox(decoration: BoxDecoration(color: Colors.red), child: Text('Hello World')), title: DecoratedBox(
decoration: BoxDecoration(color: Colors.red),
child: Text('Hello World'),
),
trailing: FlutterLogo(), trailing: FlutterLogo(),
), ),
); );

View File

@ -8,14 +8,18 @@ import 'package:flutter/material.dart';
// dirty children even without explicit repaint boundaries. These intentionally use // dirty children even without explicit repaint boundaries. These intentionally use
// text to ensure we don't measure the opacity peephole case. // text to ensure we don't measure the opacity peephole case.
class AnimatedComplexOpacity extends StatefulWidget { class AnimatedComplexOpacity extends StatefulWidget {
const AnimatedComplexOpacity({ super.key }); const AnimatedComplexOpacity({super.key});
@override @override
State<AnimatedComplexOpacity> createState() => _AnimatedComplexOpacityState(); State<AnimatedComplexOpacity> createState() => _AnimatedComplexOpacityState();
} }
class _AnimatedComplexOpacityState extends State<AnimatedComplexOpacity> with SingleTickerProviderStateMixin { class _AnimatedComplexOpacityState extends State<AnimatedComplexOpacity>
late final AnimationController controller = AnimationController(vsync: this, duration: const Duration(milliseconds: 5000)); with SingleTickerProviderStateMixin {
late final AnimationController controller = AnimationController(
vsync: this,
duration: const Duration(milliseconds: 5000),
);
late final Animation<double> animation = controller.drive(Tween<double>(begin: 0.0, end: 1.0)); late final Animation<double> animation = controller.drive(Tween<double>(begin: 0.0, end: 1.0));
@override @override
@ -37,9 +41,12 @@ class _AnimatedComplexOpacityState extends State<AnimatedComplexOpacity> with Si
body: ListView( body: ListView(
children: <Widget>[ children: <Widget>[
for (int i = 0; i < 20; i++) for (int i = 0; i < 20; i++)
FadeTransition(opacity: animation, child: Center( FadeTransition(
child: Transform.scale(scale: 1.01, child: const ModeratelyComplexWidget()), opacity: animation,
)), child: Center(
child: Transform.scale(scale: 1.01, child: const ModeratelyComplexWidget()),
),
),
], ],
), ),
), ),
@ -48,7 +55,7 @@ class _AnimatedComplexOpacityState extends State<AnimatedComplexOpacity> with Si
} }
class ModeratelyComplexWidget extends StatelessWidget { class ModeratelyComplexWidget extends StatelessWidget {
const ModeratelyComplexWidget({ super.key }); const ModeratelyComplexWidget({super.key});
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
@ -57,7 +64,10 @@ class ModeratelyComplexWidget extends StatelessWidget {
clipBehavior: Clip.hardEdge, clipBehavior: Clip.hardEdge,
child: ListTile( child: ListTile(
leading: Icon(Icons.abc, size: 24), leading: Icon(Icons.abc, size: 24),
title: DecoratedBox(decoration: BoxDecoration(color: Colors.red), child: Text('Hello World')), title: DecoratedBox(
decoration: BoxDecoration(color: Colors.red),
child: Text('Hello World'),
),
trailing: FlutterLogo(), trailing: FlutterLogo(),
), ),
); );

View File

@ -12,9 +12,7 @@ class AnimatedImagePage extends StatelessWidget {
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
return Scaffold( return Scaffold(
appBar: AppBar( appBar: AppBar(title: const Text('Animated Image')),
title: const Text('Animated Image'),
),
body: Image.asset( body: Image.asset(
'animated_images/animated_flutter_lgtm.gif', 'animated_images/animated_flutter_lgtm.gif',
package: 'flutter_gallery_assets', package: 'flutter_gallery_assets',

View File

@ -11,16 +11,18 @@ import 'package:flutter/material.dart';
/// An animated GIF image with 3 1x1 pixel frames (a red, green, and blue /// An animated GIF image with 3 1x1 pixel frames (a red, green, and blue
/// frames). The GIF animates forever, and each frame has a 100ms delay. /// frames). The GIF animates forever, and each frame has a 100ms delay.
const String kAnimatedGif = 'R0lGODlhAQABAKEDAAAA//8AAAD/AP///yH/C05FVFNDQVBFMi' const String kAnimatedGif =
'4wAwEAAAAh+QQACgD/ACwAAAAAAQABAAACAkwBACH5BAAKAP8A' 'R0lGODlhAQABAKEDAAAA//8AAAD/AP///yH/C05FVFNDQVBFMi'
'LAAAAAABAAEAAAICVAEAIfkEAAoA/wAsAAAAAAEAAQAAAgJEAQ' '4wAwEAAAAh+QQACgD/ACwAAAAAAQABAAACAkwBACH5BAAKAP8A'
'A7'; 'LAAAAAABAAEAAAICVAEAIfkEAAoA/wAsAAAAAAEAAQAAAgJEAQ'
'A7';
/// A 50x50 blue square png /// A 50x50 blue square png
const String kBlueSquare = 'iVBORw0KGgoAAAANSUhEUgAAADIAAAAyCAYAAAAeP4ixAAAASEl' const String kBlueSquare =
'EQVR42u3PMQ0AMAgAsGFjL/4tYQU08JLWQSN/9TsgRERERERERE' 'iVBORw0KGgoAAAANSUhEUgAAADIAAAAyCAYAAAAeP4ixAAAASEl'
'REREREREREREREREREREREREREREREREREREREREQ2BgNuaUcSj' 'EQVR42u3PMQ0AMAgAsGFjL/4tYQU08JLWQSN/9TsgRERERERERE'
'uqqAAAAAElFTkSuQmCC'; 'REREREREREREREREREREREREREREREREREREREREQ2BgNuaUcSj'
'uqqAAAAAElFTkSuQmCC';
/// A 10x10 grid of animated looping placeholder gifts that fade into a /// A 10x10 grid of animated looping placeholder gifts that fade into a
/// blue square. /// blue square.
@ -43,6 +45,7 @@ class AnimatedPlaceholderPage extends StatelessWidget {
} }
int _key = 0; int _key = 0;
/// An image provider that is always unique from other DelayedBase64Images and /// An image provider that is always unique from other DelayedBase64Images and
/// simulates a delay in loading. /// simulates a delay in loading.
class DelayedBase64Image extends ImageProvider<int> { class DelayedBase64Image extends ImageProvider<int> {

View File

@ -30,13 +30,7 @@ class _AnimationWithMicrotasksState extends State<AnimationWithMicrotasks> {
Widget build(BuildContext context) { Widget build(BuildContext context) {
return const Scaffold( return const Scaffold(
backgroundColor: Colors.grey, backgroundColor: Colors.grey,
body: Center( body: Center(child: SizedBox(width: 200, height: 100, child: LinearProgressIndicator())),
child: SizedBox(
width: 200,
height: 100,
child: LinearProgressIndicator(),
),
),
); );
} }
} }

View File

@ -36,25 +36,20 @@ class _BackdropFilterPageState extends State<BackdropFilterPage> with TickerProv
Widget addBlur(Widget child, bool shouldBlur) { Widget addBlur(Widget child, bool shouldBlur) {
if (shouldBlur) { if (shouldBlur) {
return ClipRect( return ClipRect(
child: BackdropFilter( child: BackdropFilter(filter: ImageFilter.blur(sigmaX: 5, sigmaY: 5), child: child),
filter: ImageFilter.blur(sigmaX: 5, sigmaY: 5),
child: child,
),
); );
} else { } else {
return child; return child;
} }
} }
final Widget txt = addBlur(Container( final Widget txt = addBlur(
padding: const EdgeInsets.all(5), Container(padding: const EdgeInsets.all(5), child: const Text('txt')),
child: const Text('txt'), _blurTexts,
), _blurTexts); );
Widget col(Widget w, int numRows) { Widget col(Widget w, int numRows) {
return Column( return Column(children: List<Widget>.generate(numRows, (int i) => w));
children: List<Widget>.generate(numRows, (int i) => w),
);
} }
Widget grid(Widget w, int numRows, int numCols) { Widget grid(Widget w, int numRows, int numCols) {
@ -74,38 +69,45 @@ class _BackdropFilterPageState extends State<BackdropFilterPage> with TickerProv
children: <Widget>[ children: <Widget>[
Expanded( Expanded(
child: RepaintBoundary( child: RepaintBoundary(
child: Center( child: Center(
child: AnimatedBuilder( child: AnimatedBuilder(
animation: animation, animation: animation,
builder: (BuildContext c, Widget? w) { builder: (BuildContext c, Widget? w) {
final int val = (animation.value * 255).round(); final int val = (animation.value * 255).round();
return Container( return Container(
width: 50, width: 50,
height: 50, height: 50,
color: Color.fromARGB(255, val, val, val)); color: Color.fromARGB(255, val, val, val),
}), );
)), },
),
),
),
), ),
const SizedBox(height: 20), const SizedBox(height: 20),
RepaintBoundary( RepaintBoundary(child: addBlur(grid(txt, 17, 5), _blurGroup)),
child: addBlur(grid(txt, 17, 5), _blurGroup),
),
const SizedBox(height: 20), const SizedBox(height: 20),
ColoredBox( ColoredBox(
color: Colors.white, color: Colors.white,
child:Row( child: Row(
mainAxisAlignment: MainAxisAlignment.center, mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[ children: <Widget>[
const Text('Backdrop per txt:'), const Text('Backdrop per txt:'),
Checkbox( Checkbox(
value: _blurTexts, value: _blurTexts,
onChanged: (bool? v) => setState(() { _blurTexts = v ?? false; }), onChanged:
(bool? v) => setState(() {
_blurTexts = v ?? false;
}),
), ),
const SizedBox(width: 10), const SizedBox(width: 10),
const Text('Backdrop grid:'), const Text('Backdrop grid:'),
Checkbox( Checkbox(
value: _blurGroup, value: _blurGroup,
onChanged: (bool? v) => setState(() { _blurGroup = v ?? false; }), onChanged:
(bool? v) => setState(() {
_blurGroup = v ?? false;
}),
), ),
], ],
), ),

View File

@ -13,8 +13,7 @@ class ClipperCachePage extends StatefulWidget {
State<ClipperCachePage> createState() => _ClipperCachePageState(); State<ClipperCachePage> createState() => _ClipperCachePageState();
} }
class _ClipperCachePageState extends State<ClipperCachePage> class _ClipperCachePageState extends State<ClipperCachePage> with TickerProviderStateMixin {
with TickerProviderStateMixin {
final double _animateOffset = 100; final double _animateOffset = 100;
final ScrollController _controller = ScrollController(); final ScrollController _controller = ScrollController();
final bool _isComplex = true; final bool _isComplex = true;
@ -25,13 +24,21 @@ class _ClipperCachePageState extends State<ClipperCachePage>
super.initState(); super.initState();
_controller.addListener(() { _controller.addListener(() {
if (_controller.offset < 10) { if (_controller.offset < 10) {
_controller.animateTo(_animateOffset, duration: const Duration(milliseconds: 1000), curve: Curves.ease); _controller.animateTo(
_animateOffset,
duration: const Duration(milliseconds: 1000),
curve: Curves.ease,
);
} else if (_controller.offset > _animateOffset - 10) { } else if (_controller.offset > _animateOffset - 10) {
_controller.animateTo(0, duration: const Duration(milliseconds: 1000), curve: Curves.ease); _controller.animateTo(0, duration: const Duration(milliseconds: 1000), curve: Curves.ease);
} }
}); });
Timer(const Duration(milliseconds: 500), () { Timer(const Duration(milliseconds: 500), () {
_controller.animateTo(_animateOffset, duration: const Duration(milliseconds: 1000), curve: Curves.ease); _controller.animateTo(
_animateOffset,
duration: const Duration(milliseconds: 1000),
curve: Curves.ease,
);
}); });
} }
@ -55,18 +62,9 @@ class _ClipperCachePageState extends State<ClipperCachePage>
controller: _controller, controller: _controller,
children: <Widget>[ children: <Widget>[
SizedBox(height: _topMargin), SizedBox(height: _topMargin),
ClipPath( ClipPath(clipBehavior: Clip.antiAliasWithSaveLayer, child: _makeChild(0, _isComplex)),
clipBehavior: Clip.antiAliasWithSaveLayer, ClipRect(clipBehavior: Clip.antiAliasWithSaveLayer, child: _makeChild(1, _isComplex)),
child: _makeChild(0, _isComplex) ClipRRect(clipBehavior: Clip.antiAliasWithSaveLayer, child: _makeChild(2, _isComplex)),
),
ClipRect(
clipBehavior: Clip.antiAliasWithSaveLayer,
child: _makeChild(1, _isComplex)
),
ClipRRect(
clipBehavior: Clip.antiAliasWithSaveLayer,
child: _makeChild(2, _isComplex)
),
const SizedBox(height: 1000), const SizedBox(height: 1000),
], ],
), ),
@ -76,11 +74,7 @@ class _ClipperCachePageState extends State<ClipperCachePage>
Widget _makeChild(int itemIndex, bool complex) { Widget _makeChild(int itemIndex, bool complex) {
final BoxDecoration decoration = BoxDecoration( final BoxDecoration decoration = BoxDecoration(
color: Colors.white70, color: Colors.white70,
boxShadow: const <BoxShadow>[ boxShadow: const <BoxShadow>[BoxShadow(blurRadius: 5.0)],
BoxShadow(
blurRadius: 5.0,
),
],
borderRadius: BorderRadius.circular(5.0), borderRadius: BorderRadius.circular(5.0),
); );
return RepaintBoundary( return RepaintBoundary(

View File

@ -15,18 +15,15 @@ class ColorFilterAndFadePage extends StatefulWidget {
State<ColorFilterAndFadePage> createState() => _ColorFilterAndFadePageState(); State<ColorFilterAndFadePage> createState() => _ColorFilterAndFadePageState();
} }
class _ColorFilterAndFadePageState extends State<ColorFilterAndFadePage> with TickerProviderStateMixin { class _ColorFilterAndFadePageState extends State<ColorFilterAndFadePage>
with TickerProviderStateMixin {
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
final Widget shadowWidget = _ShadowWidget( final Widget shadowWidget = _ShadowWidget(
width: 24, width: 24,
height: 24, height: 24,
useColorFilter: _useColorFilter, useColorFilter: _useColorFilter,
shadow: const ui.Shadow( shadow: const ui.Shadow(color: Colors.black45, offset: Offset(0.0, 2.0), blurRadius: 4.0),
color: Colors.black45,
offset: Offset(0.0, 2.0),
blurRadius: 4.0,
),
); );
final Widget row = Row( final Widget row = Row(
@ -45,17 +42,18 @@ class _ColorFilterAndFadePageState extends State<ColorFilterAndFadePage> with Ti
], ],
); );
final Widget column = Column(mainAxisAlignment: MainAxisAlignment.center, final Widget column = Column(
children: <Widget>[ mainAxisAlignment: MainAxisAlignment.center,
row, children: <Widget>[
const SizedBox(height: 12), row,
row, const SizedBox(height: 12),
const SizedBox(height: 12), row,
row, const SizedBox(height: 12),
const SizedBox(height: 12), row,
row, const SizedBox(height: 12),
const SizedBox(height: 12), row,
], const SizedBox(height: 12),
],
); );
final Widget fadeTransition = FadeTransition( final Widget fadeTransition = FadeTransition(
@ -63,31 +61,29 @@ class _ColorFilterAndFadePageState extends State<ColorFilterAndFadePage> with Ti
// This RepaintBoundary is necessary to not let the opacity change // This RepaintBoundary is necessary to not let the opacity change
// invalidate the layer raster cache below. This is necessary with // invalidate the layer raster cache below. This is necessary with
// or without the color filter. // or without the color filter.
child: RepaintBoundary( child: RepaintBoundary(child: column),
child: column,
),
); );
return Scaffold( return Scaffold(
backgroundColor: Colors.lightBlue, backgroundColor: Colors.lightBlue,
body: Center( body: Center(
child: Column( child: Column(
mainAxisSize: MainAxisSize.min, mainAxisSize: MainAxisSize.min,
children: <Widget>[ children: <Widget>[
fadeTransition, fadeTransition,
Container(height: 20), Container(height: 20),
const Text('Use Color Filter:'), const Text('Use Color Filter:'),
Checkbox( Checkbox(
value: _useColorFilter, value: _useColorFilter,
onChanged: (bool? value) { onChanged: (bool? value) {
setState(() { setState(() {
_useColorFilter = value ?? false; _useColorFilter = value ?? false;
}); });
}, },
),
],
), ),
],
), ),
),
); );
} }
@ -141,10 +137,7 @@ class _ShadowWidget extends StatelessWidget {
width: width, width: width,
height: height, height: height,
child: CustomPaint( child: CustomPaint(
painter: _ShadowPainter( painter: _ShadowPainter(useColorFilter: useColorFilter, shadow: shadow),
useColorFilter: useColorFilter,
shadow: shadow,
),
size: Size(width, height), size: Size(width, height),
isComplex: true, isComplex: true,
), ),
@ -170,7 +163,10 @@ class _ShadowPainter extends CustomPainter {
canvas.saveLayer(null, paint); canvas.saveLayer(null, paint);
canvas.translate(shadow.offset.dx, shadow.offset.dy); canvas.translate(shadow.offset.dx, shadow.offset.dy);
canvas.drawRect(rect, Paint()); canvas.drawRect(rect, Paint());
canvas.drawRect(rect, Paint()..maskFilter = MaskFilter.blur(BlurStyle.normal, shadow.blurSigma)); canvas.drawRect(
rect,
Paint()..maskFilter = MaskFilter.blur(BlurStyle.normal, shadow.blurSigma),
);
canvas.restore(); canvas.restore();
canvas.drawRect(rect, Paint()..color = useColorFilter ? Colors.white : Colors.black); canvas.drawRect(rect, Paint()..color = useColorFilter ? Colors.white : Colors.black);

View File

@ -11,15 +11,18 @@ class ColorFilterCachePage extends StatefulWidget {
State<ColorFilterCachePage> createState() => _ColorFilterCachePageState(); State<ColorFilterCachePage> createState() => _ColorFilterCachePageState();
} }
class _ColorFilterCachePageState extends State<ColorFilterCachePage> class _ColorFilterCachePageState extends State<ColorFilterCachePage> with TickerProviderStateMixin {
with TickerProviderStateMixin {
final ScrollController _controller = ScrollController(); final ScrollController _controller = ScrollController();
@override @override
void initState() { void initState() {
super.initState(); super.initState();
_controller.addListener(() { _controller.addListener(() {
if (_controller.offset < 20) { if (_controller.offset < 20) {
_controller.animateTo(150, duration: const Duration(milliseconds: 1000), curve: Curves.ease); _controller.animateTo(
150,
duration: const Duration(milliseconds: 1000),
curve: Curves.ease,
);
} else if (_controller.offset > 130) { } else if (_controller.offset > 130) {
_controller.animateTo(0, duration: const Duration(milliseconds: 1000), curve: Curves.ease); _controller.animateTo(0, duration: const Duration(milliseconds: 1000), curve: Curves.ease);
} }
@ -41,12 +44,11 @@ class _ColorFilterCachePageState extends State<ColorFilterCachePage>
colorFilter: ColorFilter.mode(Colors.green[300]!, BlendMode.luminosity), colorFilter: ColorFilter.mode(Colors.green[300]!, BlendMode.luminosity),
child: Container( child: Container(
clipBehavior: Clip.antiAlias, clipBehavior: Clip.antiAlias,
decoration: const BoxDecoration(boxShadow: <BoxShadow>[ decoration: const BoxDecoration(
BoxShadow( boxShadow: <BoxShadow>[BoxShadow(color: Colors.red, blurRadius: 5.0)],
color: Colors.red, color: Colors.blue,
blurRadius: 5.0, backgroundBlendMode: BlendMode.luminosity,
), ),
], color: Colors.blue, backgroundBlendMode: BlendMode.luminosity),
child: Column( child: Column(
children: <Widget>[ children: <Widget>[
const Text('Color Filter Cache Pref Test'), const Text('Color Filter Cache Pref Test'),

View File

@ -11,7 +11,8 @@ class ColorFilterWithUnstableChildPage extends StatefulWidget {
State<StatefulWidget> createState() => _ColorFilterWithUnstableChildPageState(); State<StatefulWidget> createState() => _ColorFilterWithUnstableChildPageState();
} }
class _ColorFilterWithUnstableChildPageState extends State<ColorFilterWithUnstableChildPage> with SingleTickerProviderStateMixin { class _ColorFilterWithUnstableChildPageState extends State<ColorFilterWithUnstableChildPage>
with SingleTickerProviderStateMixin {
late Animation<double> _offsetY; late Animation<double> _offsetY;
late AnimationController _controller; late AnimationController _controller;
@ -34,21 +35,27 @@ class _ColorFilterWithUnstableChildPageState extends State<ColorFilterWithUnstab
return AnimatedBuilder( return AnimatedBuilder(
animation: _offsetY, animation: _offsetY,
builder: (BuildContext context, Widget? child) { builder: (BuildContext context, Widget? child) {
return Stack(children: List<Widget>.generate(50, (int i) => Positioned( return Stack(
left: 0, children: List<Widget>.generate(
top: (200 * i).toDouble() + _offsetY.value, 50,
child: ColorFiltered( (int i) => Positioned(
colorFilter: ColorFilter.mode(Colors.green[300]!, BlendMode.luminosity), left: 0,
child: RepaintBoundary( top: (200 * i).toDouble() + _offsetY.value,
child: Container( child: ColorFiltered(
// Slightly change width to invalidate raster cache. colorFilter: ColorFilter.mode(Colors.green[300]!, BlendMode.luminosity),
width: 1000 - (_offsetY.value / 100), child: RepaintBoundary(
height: 100, color: Colors.red, child: Container(
// Slightly change width to invalidate raster cache.
width: 1000 - (_offsetY.value / 100),
height: 100,
color: Colors.red,
),
), ),
), ),
), ),
))); ),
} );
},
); );
} }
} }

View File

@ -15,9 +15,7 @@ class CubicBezierPage extends StatelessWidget {
return const Center( return const Center(
child: Column( child: Column(
mainAxisAlignment: MainAxisAlignment.center, mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[ children: <Widget>[Bezier(Colors.amber, 1.0)],
Bezier(Colors.amber, 1.0),
],
), ),
); );
} }
@ -47,8 +45,7 @@ class Bezier extends StatelessWidget {
bezier2Path.cubicTo(0.0, 70.55, 42.0, 31.55, 69.91, 14.77); bezier2Path.cubicTo(0.0, 70.55, 42.0, 31.55, 69.91, 14.77);
bezier2Path.cubicTo(97.82, -2.01, 149.24, -20.93, 104.37, 59.39); bezier2Path.cubicTo(97.82, -2.01, 149.24, -20.93, 104.37, 59.39);
paths.add(PathDetail(bezier2Path, paths.add(PathDetail(bezier2Path, translate: <double>[29.45, 151.0], rotation: -1.5708));
translate: <double>[29.45, 151.0], rotation: -1.5708));
// Path 3 // Path 3
final Path bezier3Path = Path(); final Path bezier3Path = Path();
@ -56,8 +53,7 @@ class Bezier extends StatelessWidget {
bezier3Path.cubicTo(0.0, 69.48, 44.82, 27.92, 69.91, 13.7); bezier3Path.cubicTo(0.0, 69.48, 44.82, 27.92, 69.91, 13.7);
bezier3Path.cubicTo(95.0, -0.52, 149.24, -22.0, 104.37, 58.32); bezier3Path.cubicTo(95.0, -0.52, 149.24, -22.0, 104.37, 58.32);
paths.add(PathDetail(bezier3Path, paths.add(PathDetail(bezier3Path, translate: <double>[53.0, 200.48], rotation: -3.14159));
translate: <double>[53.0, 200.48], rotation: -3.14159));
// Path 4 // Path 4
final Path bezier4Path = Path(); final Path bezier4Path = Path();
@ -65,22 +61,22 @@ class Bezier extends StatelessWidget {
bezier4Path.cubicTo(0.0, 69.48, 43.82, 27.92, 69.91, 13.7); bezier4Path.cubicTo(0.0, 69.48, 43.82, 27.92, 69.91, 13.7);
bezier4Path.cubicTo(96.0, -0.52, 149.24, -22.0, 104.37, 58.32); bezier4Path.cubicTo(96.0, -0.52, 149.24, -22.0, 104.37, 58.32);
paths.add(PathDetail(bezier4Path, paths.add(PathDetail(bezier4Path, translate: <double>[122.48, 77.0], rotation: -4.71239));
translate: <double>[122.48, 77.0], rotation: -4.71239));
return paths; return paths;
} }
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
return Stack(children: <Widget>[ return Stack(
CustomPaint( children: <Widget>[
foregroundPainter: CustomPaint(
BezierPainter(Colors.grey, 0.0, _getLogoPath(), false), foregroundPainter: BezierPainter(Colors.grey, 0.0, _getLogoPath(), false),
size: const Size(100.0, 100.0), size: const Size(100.0, 100.0),
), ),
AnimatedBezier(color, scale, blur: blur), AnimatedBezier(color, scale, blur: blur),
]); ],
);
} }
} }
@ -110,17 +106,11 @@ class Point {
double y; double y;
} }
class AnimatedBezierState extends State<AnimatedBezier> class AnimatedBezierState extends State<AnimatedBezier> with SingleTickerProviderStateMixin {
with SingleTickerProviderStateMixin {
late AnimationController controller; late AnimationController controller;
late CurvedAnimation curve; late CurvedAnimation curve;
bool isPlaying = false; bool isPlaying = false;
List<List<Point>> pointList = <List<Point>>[ List<List<Point>> pointList = <List<Point>>[<Point>[], <Point>[], <Point>[], <Point>[]];
<Point>[],
<Point>[],
<Point>[],
<Point>[],
];
bool isReversed = false; bool isReversed = false;
List<PathDetail> _playForward() { List<PathDetail> _playForward() {
@ -169,8 +159,7 @@ class AnimatedBezierState extends State<AnimatedBezier>
bezier2Path.lineTo(p.x, p.y); bezier2Path.lineTo(p.x, p.y);
} }
paths.add(PathDetail(bezier2Path, paths.add(PathDetail(bezier2Path, translate: <double>[29.45, 151.0], rotation: -1.5708));
translate: <double>[29.45, 151.0], rotation: -1.5708));
// Path 3 // Path 3
final Path bezier3Path = Path(); final Path bezier3Path = Path();
@ -190,8 +179,7 @@ class AnimatedBezierState extends State<AnimatedBezier>
bezier3Path.lineTo(p.x, p.y); bezier3Path.lineTo(p.x, p.y);
} }
paths.add(PathDetail(bezier3Path, paths.add(PathDetail(bezier3Path, translate: <double>[53.0, 200.48], rotation: -3.14159));
translate: <double>[53.0, 200.48], rotation: -3.14159));
// Path 4 // Path 4
final Path bezier4Path = Path(); final Path bezier4Path = Path();
@ -212,8 +200,7 @@ class AnimatedBezierState extends State<AnimatedBezier>
bezier4Path.lineTo(p.x, p.y); bezier4Path.lineTo(p.x, p.y);
} }
paths.add(PathDetail(bezier4Path, paths.add(PathDetail(bezier4Path, translate: <double>[122.48, 77.0], rotation: -4.71239));
translate: <double>[122.48, 77.0], rotation: -4.71239));
return paths; return paths;
} }
@ -260,8 +247,7 @@ class AnimatedBezierState extends State<AnimatedBezier>
return <PathDetail>[ return <PathDetail>[
PathDetail(path), PathDetail(path),
PathDetail(bezier2Path, translate: <double>[29.45, 151.0], rotation: -1.5708), PathDetail(bezier2Path, translate: <double>[29.45, 151.0], rotation: -1.5708),
PathDetail(bezier3Path, PathDetail(bezier3Path, translate: <double>[53.0, 200.48], rotation: -3.14159),
translate: <double>[53.0, 200.48], rotation: -3.14159),
PathDetail(bezier4Path, translate: <double>[122.48, 77.0], rotation: -4.71239), PathDetail(bezier4Path, translate: <double>[122.48, 77.0], rotation: -4.71239),
]; ];
} }
@ -308,23 +294,23 @@ class AnimatedBezierState extends State<AnimatedBezier>
@override @override
void initState() { void initState() {
super.initState(); super.initState();
controller = AnimationController( controller = AnimationController(vsync: this, duration: const Duration(milliseconds: 1000));
vsync: this, duration: const Duration(milliseconds: 1000));
// Animations are typically implemented using the AnimatedBuilder widget. // Animations are typically implemented using the AnimatedBuilder widget.
// This code uses a manual listener for historical reasons and will remain // This code uses a manual listener for historical reasons and will remain
// in order to preserve compatibility with the history of measurements for // in order to preserve compatibility with the history of measurements for
// this benchmark. // this benchmark.
curve = CurvedAnimation(parent: controller, curve: Curves.linear) curve =
..addListener(() { CurvedAnimation(parent: controller, curve: Curves.linear)
setState(() {}); ..addListener(() {
}) setState(() {});
..addStatusListener((AnimationStatus status) { })
if (status.isCompleted) { ..addStatusListener((AnimationStatus status) {
reverseAnimation(); if (status.isCompleted) {
} else if (status.isDismissed) { reverseAnimation();
playAnimation(); } else if (status.isDismissed) {
} playAnimation();
}); }
});
playAnimation(); playAnimation();
} }
@ -338,9 +324,14 @@ class AnimatedBezierState extends State<AnimatedBezier>
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
return CustomPaint( return CustomPaint(
foregroundPainter: BezierPainter(widget.color, foregroundPainter: BezierPainter(
curve.value * widget.blur, _getLogoPath(), isPlaying), widget.color,
size: const Size(100.0, 100.0)); curve.value * widget.blur,
_getLogoPath(),
isPlaying,
),
size: const Size(100.0, 100.0),
);
} }
} }

View File

@ -38,19 +38,25 @@ class _CullOpacityPageState extends State<CullOpacityPage> with SingleTickerProv
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
return Stack(children: List<Widget>.generate(50, (int i) => Positioned( return Stack(
left: 0, children: List<Widget>.generate(
top: (200 * i).toDouble() + _offsetY.value, 50,
child: Opacity( (int i) => Positioned(
opacity: 0.5, left: 0,
child: RepaintBoundary( top: (200 * i).toDouble() + _offsetY.value,
child: Container( child: Opacity(
// Slightly change width to invalidate raster cache. opacity: 0.5,
width: 1000 - (_offsetY.value / 100), child: RepaintBoundary(
height: 100, color: Colors.red, child: Container(
// Slightly change width to invalidate raster cache.
width: 1000 - (_offsetY.value / 100),
height: 100,
color: Colors.red,
),
),
), ),
), ),
), ),
))); );
} }
} }

View File

@ -7,13 +7,13 @@ import 'dart:ui' as ui;
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
Future<ui.Image> loadImage(String asset) async { Future<ui.Image> loadImage(String asset) async {
final ui.ImmutableBuffer buffer = await ui.ImmutableBuffer.fromAsset(asset); final ui.ImmutableBuffer buffer = await ui.ImmutableBuffer.fromAsset(asset);
final ui.Codec codec = await PaintingBinding.instance.instantiateImageCodecWithSize(buffer); final ui.Codec codec = await PaintingBinding.instance.instantiateImageCodecWithSize(buffer);
final ui.FrameInfo frameInfo = await codec.getNextFrame(); final ui.FrameInfo frameInfo = await codec.getNextFrame();
return frameInfo.image; return frameInfo.image;
} }
class DrawAtlasPage extends StatefulWidget { class DrawAtlasPage extends StatefulWidget {
const DrawAtlasPage({super.key}); const DrawAtlasPage({super.key});
@override @override
@ -28,7 +28,9 @@ class _DrawAtlasPageState extends State<DrawAtlasPage> with SingleTickerProvider
@override @override
void initState() { void initState() {
super.initState(); super.initState();
loadImage('packages/flutter_gallery_assets/food/butternut_squash_soup.png').then((ui.Image pending) { loadImage('packages/flutter_gallery_assets/food/butternut_squash_soup.png').then((
ui.Image pending,
) {
setState(() { setState(() {
image = pending; image = pending;
}); });
@ -48,7 +50,6 @@ class _DrawAtlasPageState extends State<DrawAtlasPage> with SingleTickerProvider
super.dispose(); super.dispose();
} }
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
if (image == null) { if (image == null) {
@ -73,39 +74,75 @@ class VerticesPainter extends CustomPainter {
canvas.translate(0, tick); canvas.translate(0, tick);
canvas.drawAtlas( canvas.drawAtlas(
image, image,
<RSTransform>[RSTransform.fromComponents(rotation: 0, scale: 1, anchorX: 0, anchorY: 0, translateX: 0, translateY: 0)], <RSTransform>[
RSTransform.fromComponents(
rotation: 0,
scale: 1,
anchorX: 0,
anchorY: 0,
translateX: 0,
translateY: 0,
),
],
<Rect>[Rect.fromLTWH(0, 0, image.width.toDouble(), image.height.toDouble())], <Rect>[Rect.fromLTWH(0, 0, image.width.toDouble(), image.height.toDouble())],
<Color>[Colors.red], <Color>[Colors.red],
BlendMode.plus, BlendMode.plus,
null, null,
Paint() Paint(),
); );
canvas.drawAtlas( canvas.drawAtlas(
image, image,
<RSTransform>[RSTransform.fromComponents(rotation: 0, scale: 1, anchorX: 0, anchorY: 0, translateX: 250, translateY: 0)], <RSTransform>[
RSTransform.fromComponents(
rotation: 0,
scale: 1,
anchorX: 0,
anchorY: 0,
translateX: 250,
translateY: 0,
),
],
<Rect>[Rect.fromLTWH(0, 0, image.width.toDouble(), image.height.toDouble())], <Rect>[Rect.fromLTWH(0, 0, image.width.toDouble(), image.height.toDouble())],
<Color>[Colors.green], <Color>[Colors.green],
BlendMode.plus, BlendMode.plus,
null, null,
Paint() Paint(),
); );
canvas.drawAtlas( canvas.drawAtlas(
image, image,
<RSTransform>[RSTransform.fromComponents(rotation: 0, scale: 1, anchorX: 0, anchorY: 0, translateX: 0, translateY: 250)], <RSTransform>[
RSTransform.fromComponents(
rotation: 0,
scale: 1,
anchorX: 0,
anchorY: 0,
translateX: 0,
translateY: 250,
),
],
<Rect>[Rect.fromLTWH(0, 0, image.width.toDouble(), image.height.toDouble())], <Rect>[Rect.fromLTWH(0, 0, image.width.toDouble(), image.height.toDouble())],
<Color>[Colors.blue], <Color>[Colors.blue],
BlendMode.plus, BlendMode.plus,
null, null,
Paint() Paint(),
); );
canvas.drawAtlas( canvas.drawAtlas(
image, image,
<RSTransform>[RSTransform.fromComponents(rotation: 0, scale: 1, anchorX: 0, anchorY: 0, translateX: 250, translateY: 250)], <RSTransform>[
RSTransform.fromComponents(
rotation: 0,
scale: 1,
anchorX: 0,
anchorY: 0,
translateX: 250,
translateY: 250,
),
],
<Rect>[Rect.fromLTWH(0, 0, image.width.toDouble(), image.height.toDouble())], <Rect>[Rect.fromLTWH(0, 0, image.width.toDouble(), image.height.toDouble())],
<Color>[Colors.yellow], <Color>[Colors.yellow],
BlendMode.plus, BlendMode.plus,
null, null,
Paint() Paint(),
); );
} }

View File

@ -7,7 +7,7 @@ import 'dart:ui';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
class DrawPointsPage extends StatefulWidget { class DrawPointsPage extends StatefulWidget {
const DrawPointsPage({super.key}); const DrawPointsPage({super.key});
@override @override
@ -36,7 +36,6 @@ class _DrawPointsPageState extends State<DrawPointsPage> with SingleTickerProvid
super.dispose(); super.dispose();
} }
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
return CustomPaint( return CustomPaint(
@ -77,11 +76,12 @@ class PointsPainter extends CustomPainter {
data[j] = x; data[j] = x;
data[j + 1] = (size.height / (j + 1)) + 200; data[j + 1] = (size.height / (j + 1)) + 200;
} }
final Paint paint = Paint() final Paint paint =
..color = kColors[i] Paint()
..strokeWidth = 5 ..color = kColors[i]
..strokeCap = StrokeCap.round ..strokeWidth = 5
..style = PaintingStyle.stroke; ..strokeCap = StrokeCap.round
..style = PaintingStyle.stroke;
canvas.drawRawPoints(PointMode.points, data, paint); canvas.drawRawPoints(PointMode.points, data, paint);
} }
} }

View File

@ -7,13 +7,13 @@ import 'dart:ui' as ui;
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
Future<ui.Image> loadImage(String asset) async { Future<ui.Image> loadImage(String asset) async {
final ui.ImmutableBuffer buffer = await ui.ImmutableBuffer.fromAsset(asset); final ui.ImmutableBuffer buffer = await ui.ImmutableBuffer.fromAsset(asset);
final ui.Codec codec = await PaintingBinding.instance.instantiateImageCodecWithSize(buffer); final ui.Codec codec = await PaintingBinding.instance.instantiateImageCodecWithSize(buffer);
final ui.FrameInfo frameInfo = await codec.getNextFrame(); final ui.FrameInfo frameInfo = await codec.getNextFrame();
return frameInfo.image; return frameInfo.image;
} }
class DrawVerticesPage extends StatefulWidget { class DrawVerticesPage extends StatefulWidget {
const DrawVerticesPage({super.key}); const DrawVerticesPage({super.key});
@override @override
@ -28,7 +28,9 @@ class _DrawVerticesPageState extends State<DrawVerticesPage> with SingleTickerPr
@override @override
void initState() { void initState() {
super.initState(); super.initState();
loadImage('packages/flutter_gallery_assets/food/butternut_squash_soup.png').then((ui.Image pending) { loadImage('packages/flutter_gallery_assets/food/butternut_squash_soup.png').then((
ui.Image pending,
) {
setState(() { setState(() {
image = pending; image = pending;
}); });
@ -48,7 +50,6 @@ class _DrawVerticesPageState extends State<DrawVerticesPage> with SingleTickerPr
super.dispose(); super.dispose();
} }
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
if (image == null) { if (image == null) {
@ -79,7 +80,7 @@ class VerticesPainter extends CustomPainter {
Offset(250, 0), Offset(250, 0),
Offset(0, 250), Offset(0, 250),
Offset(250, 0), Offset(250, 0),
Offset(250, 250) Offset(250, 250),
], ],
textureCoordinates: <Offset>[ textureCoordinates: <Offset>[
Offset.zero, Offset.zero,
@ -87,24 +88,37 @@ class VerticesPainter extends CustomPainter {
Offset(image.width.toDouble(), 0), Offset(image.width.toDouble(), 0),
Offset(0, image.height.toDouble()), Offset(0, image.height.toDouble()),
Offset(image.width.toDouble(), 0), Offset(image.width.toDouble(), 0),
Offset(image.width.toDouble(), image.height.toDouble()) Offset(image.width.toDouble(), image.height.toDouble()),
], ],
colors: <Color>[ colors: <Color>[Colors.red, Colors.blue, Colors.green, Colors.red, Colors.blue, Colors.green],
Colors.red, );
Colors.blue, canvas.drawVertices(
Colors.green, vertices,
Colors.red, BlendMode.plus,
Colors.blue, Paint()
Colors.green, ..shader = ImageShader(image, TileMode.clamp, TileMode.clamp, Matrix4.identity().storage),
]
); );
canvas.drawVertices(vertices, BlendMode.plus, Paint()..shader = ImageShader(image, TileMode.clamp, TileMode.clamp, Matrix4.identity().storage));
canvas.translate(250, 0); canvas.translate(250, 0);
canvas.drawVertices(vertices, BlendMode.plus, Paint()..shader = ImageShader(image, TileMode.clamp, TileMode.clamp, Matrix4.identity().storage)); canvas.drawVertices(
vertices,
BlendMode.plus,
Paint()
..shader = ImageShader(image, TileMode.clamp, TileMode.clamp, Matrix4.identity().storage),
);
canvas.translate(0, 250); canvas.translate(0, 250);
canvas.drawVertices(vertices, BlendMode.plus, Paint()..shader = ImageShader(image, TileMode.clamp, TileMode.clamp, Matrix4.identity().storage)); canvas.drawVertices(
vertices,
BlendMode.plus,
Paint()
..shader = ImageShader(image, TileMode.clamp, TileMode.clamp, Matrix4.identity().storage),
);
canvas.translate(-250, 0); canvas.translate(-250, 0);
canvas.drawVertices(vertices, BlendMode.plus, Paint()..shader = ImageShader(image, TileMode.clamp, TileMode.clamp, Matrix4.identity().storage)); canvas.drawVertices(
vertices,
BlendMode.plus,
Paint()
..shader = ImageShader(image, TileMode.clamp, TileMode.clamp, Matrix4.identity().storage),
);
} }
@override @override

View File

@ -7,12 +7,11 @@ import 'dart:ui';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
enum FilterType { enum FilterType { opacity, rotateTransform, rotateFilter }
opacity, rotateTransform, rotateFilter,
}
class FilteredChildAnimationPage extends StatefulWidget { class FilteredChildAnimationPage extends StatefulWidget {
const FilteredChildAnimationPage(this.initialFilterType, { const FilteredChildAnimationPage(
this.initialFilterType, {
super.key, super.key,
this.initialComplexChild = true, this.initialComplexChild = true,
this.initialUseRepaintBoundary = true, this.initialUseRepaintBoundary = true,
@ -26,7 +25,8 @@ class FilteredChildAnimationPage extends StatefulWidget {
State<FilteredChildAnimationPage> createState() => _FilteredChildAnimationPageState(); State<FilteredChildAnimationPage> createState() => _FilteredChildAnimationPageState();
} }
class _FilteredChildAnimationPageState extends State<FilteredChildAnimationPage> with SingleTickerProviderStateMixin { class _FilteredChildAnimationPageState extends State<FilteredChildAnimationPage>
with SingleTickerProviderStateMixin {
late AnimationController _controller; late AnimationController _controller;
final GlobalKey _childKey = GlobalKey(debugLabel: 'child to animate'); final GlobalKey _childKey = GlobalKey(debugLabel: 'child to animate');
Offset _childCenter = Offset.zero; Offset _childCenter = Offset.zero;
@ -60,20 +60,16 @@ class _FilteredChildAnimationPageState extends State<FilteredChildAnimationPage>
} }
String get _title => switch (_filterType) { String get _title => switch (_filterType) {
FilterType.opacity => 'Fading Child Animation', FilterType.opacity => 'Fading Child Animation',
FilterType.rotateTransform => 'Transformed Child Animation', FilterType.rotateTransform => 'Transformed Child Animation',
FilterType.rotateFilter => 'Matrix Filtered Child Animation', FilterType.rotateFilter => 'Matrix Filtered Child Animation',
null => 'Static Child', null => 'Static Child',
}; };
static Widget _makeChild(int rows, int cols, double fontSize, bool complex) { static Widget _makeChild(int rows, int cols, double fontSize, bool complex) {
final BoxDecoration decoration = BoxDecoration( final BoxDecoration decoration = BoxDecoration(
color: Colors.green, color: Colors.green,
boxShadow: complex ? <BoxShadow>[ boxShadow: complex ? <BoxShadow>[const BoxShadow(blurRadius: 10.0)] : null,
const BoxShadow(
blurRadius: 10.0,
),
] : null,
borderRadius: BorderRadius.circular(10.0), borderRadius: BorderRadius.circular(10.0),
); );
return Stack( return Stack(
@ -81,20 +77,21 @@ class _FilteredChildAnimationPageState extends State<FilteredChildAnimationPage>
children: <Widget>[ children: <Widget>[
Column( Column(
mainAxisAlignment: MainAxisAlignment.spaceEvenly, mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: List<Widget>.generate(rows, (int r) => Row( children: List<Widget>.generate(
mainAxisAlignment: MainAxisAlignment.spaceEvenly, rows,
children: List<Widget>.generate(cols, (int c) => Container( (int r) => Row(
decoration: decoration, mainAxisAlignment: MainAxisAlignment.spaceEvenly,
child: Text('text', style: TextStyle(fontSize: fontSize)), children: List<Widget>.generate(
)), cols,
)), (int c) => Container(
), decoration: decoration,
const Text('child', child: Text('text', style: TextStyle(fontSize: fontSize)),
style: TextStyle( ),
color: Colors.blue, ),
fontSize: 36, ),
), ),
), ),
const Text('child', style: TextStyle(color: Colors.blue, fontSize: 36)),
], ],
); );
} }
@ -109,27 +106,29 @@ class _FilteredChildAnimationPageState extends State<FilteredChildAnimationPage>
Widget Function(BuildContext, Widget?) builder; Widget Function(BuildContext, Widget?) builder;
switch (filterType) { switch (filterType) {
case FilterType.opacity: case FilterType.opacity:
builder = (BuildContext context, Widget? child) => Opacity( builder =
opacity: (_controller.value * 2.0 - 1.0).abs(), (BuildContext context, Widget? child) =>
child: child, Opacity(opacity: (_controller.value * 2.0 - 1.0).abs(), child: child);
);
case FilterType.rotateTransform: case FilterType.rotateTransform:
builder = (BuildContext context, Widget? child) => Transform( builder =
transform: Matrix4.rotationZ(_controller.value * 2.0 * pi), (BuildContext context, Widget? child) => Transform(
alignment: Alignment.center, transform: Matrix4.rotationZ(_controller.value * 2.0 * pi),
filterQuality: FilterQuality.low, alignment: Alignment.center,
child: child, filterQuality: FilterQuality.low,
); child: child,
);
case FilterType.rotateFilter: case FilterType.rotateFilter:
builder = (BuildContext context, Widget? child) => ImageFiltered( builder =
imageFilter: ImageFilter.matrix(( (BuildContext context, Widget? child) => ImageFiltered(
Matrix4.identity() imageFilter: ImageFilter.matrix(
..translate(_childCenter.dx, _childCenter.dy) (Matrix4.identity()
..rotateZ(_controller.value * 2.0 * pi) ..translate(_childCenter.dx, _childCenter.dy)
..translate(- _childCenter.dx, - _childCenter.dy) ..rotateZ(_controller.value * 2.0 * pi)
).storage), ..translate(-_childCenter.dx, -_childCenter.dy))
child: child, .storage,
); ),
child: child,
);
} }
return RepaintBoundary( return RepaintBoundary(
child: AnimatedBuilder( child: AnimatedBuilder(
@ -143,9 +142,7 @@ class _FilteredChildAnimationPageState extends State<FilteredChildAnimationPage>
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
return Scaffold( return Scaffold(
appBar: AppBar( appBar: AppBar(title: Text(_title)),
title: Text(_title),
),
body: Center( body: Center(
child: _animate( child: _animate(
child: Container( child: Container(
@ -153,9 +150,7 @@ class _FilteredChildAnimationPageState extends State<FilteredChildAnimationPage>
color: Colors.yellow, color: Colors.yellow,
width: 300, width: 300,
height: 300, height: 300,
child: Center( child: Center(child: _makeChild(4, 3, 24.0, _complexChild)),
child: _makeChild(4, 3, 24.0, _complexChild),
),
), ),
protectChild: _useRepaintBoundary, protectChild: _useRepaintBoundary,
), ),

View File

@ -4,48 +4,49 @@
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
const String textLotsOfText = 'Lorem ipsum dolor sit amet, consectetur ' const String textLotsOfText =
'adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna ' 'Lorem ipsum dolor sit amet, consectetur '
'aliqua. Odio facilisis mauris sit amet massa. Tellus pellentesque eu ' 'adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna '
'tincidunt tortor aliquam nulla facilisi cras fermentum. Sit amet risus nullam ' 'aliqua. Odio facilisis mauris sit amet massa. Tellus pellentesque eu '
'eget felis eget nunc. Placerat in egestas erat imperdiet sed. Vestibulum ' 'tincidunt tortor aliquam nulla facilisi cras fermentum. Sit amet risus nullam '
'mattis ullamcorper velit sed. At auctor urna nunc id cursus metus aliquam. In ' 'eget felis eget nunc. Placerat in egestas erat imperdiet sed. Vestibulum '
'nibh mauris cursus mattis. Quis blandit turpis cursus in hac habitasse platea ' 'mattis ullamcorper velit sed. At auctor urna nunc id cursus metus aliquam. In '
'dictumst. Orci a scelerisque purus semper eget duis at tellus. At tempor ' 'nibh mauris cursus mattis. Quis blandit turpis cursus in hac habitasse platea '
'commodo ullamcorper a lacus. At auctor urna nunc id cursus metus aliquam ' 'dictumst. Orci a scelerisque purus semper eget duis at tellus. At tempor '
'eleifend. Sagittis aliquam malesuada bibendum arcu vitae elementum. Massa sed ' 'commodo ullamcorper a lacus. At auctor urna nunc id cursus metus aliquam '
'elementum tempus egestas sed sed risus. Amet consectetur adipiscing elit ut ' 'eleifend. Sagittis aliquam malesuada bibendum arcu vitae elementum. Massa sed '
'aliquam purus sit amet luctus. Elementum nisi quis eleifend quam adipiscing ' 'elementum tempus egestas sed sed risus. Amet consectetur adipiscing elit ut '
'vitae. Aliquam sem fringilla ut morbi tincidunt augue. ' 'aliquam purus sit amet luctus. Elementum nisi quis eleifend quam adipiscing '
'👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦' 'vitae. Aliquam sem fringilla ut morbi tincidunt augue. '
'👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦' '👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦'
'👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦' '👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦'
'👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦' '👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦'
'👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦' '👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦'
'👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦' '👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦'
'👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦' '👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦'
'👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦' '👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦'
'👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦' '👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦'
'👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦' '👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦'
'👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦' '👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦'
'👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦' '👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦'
'👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦' '👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦'
'👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦' '👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦'
'👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦' '👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦'
'👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦 ' '👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦'
'😀 😃 😄 😁 😆 😅 😂 🤣 🥲 ☺️ 😊 😇 🙂 🙃 😉 😌 😍 🥰 😘 😗 😙 ' '👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦 '
'😚 😋 😛 😝 😜 🤪 🤨 🧐 🤓 😎 🥸 🤩 🥳 😏 😒 😞 😔 😟 😕 🙁 ☹ ' '😀 😃 😄 😁 😆 😅 😂 🤣 🥲 ☺️ 😊 😇 🙂 🙃 😉 😌 😍 🥰 😘 😗 😙 '
'️😣 😖 😫 😩 🥺 😢 😭 😤 😠 😡 🤬 🤯 😳 🥵 🥶 😱 😨 😰 😥 😓 ' '😚 😋 😛 😝 😜 🤪 🤨 🧐 🤓 😎 🥸 🤩 🥳 😏 😒 😞 😔 😟 😕 🙁 ☹ '
'🤗 🤔 🤭 🤫 🤥 😶 😐 😑 😬 🙄 😯 😦 😧 😮 😲 🥱 😴 🤤 😪 😵 ' '️😣 😖 😫 😩 🥺 😢 😭 😤 😠 😡 🤬 🤯 😳 🥵 🥶 😱 😨 😰 😥 😓 '
'🤐 🥴 🤢 🤮 🤧 😷 🤒 🤕 🤑 🤠 😈 👿 👹 👺 🤡 💩 👻 💀 ☠️ 👽 ' '🤗 🤔 🤭 🤫 🤥 😶 😐 😑 😬 🙄 😯 😦 😧 😮 😲 🥱 😴 🤤 😪 😵 '
'👾 🤖 🎃 😺 😸 😹 😻 😼 😽 🙀 😿 😾 ' '🤐 🥴 🤢 🤮 🤧 😷 🤒 🤕 🤑 🤠 😈 👿 👹 👺 🤡 💩 👻 💀 ☠️ 👽 '
'️😣 😖 😫 😩 🥺 😢 😭 😤 😠 😡 🤬 🤯 😳 🥵 🥶 😱 😨 😰 😥 😓 ' '👾 🤖 🎃 😺 😸 😹 😻 😼 😽 🙀 😿 😾 '
'🤗 🤔 🤭 🤫 🤥 😶 😐 😑 😬 🙄 😯 😦 😧 😮 😲 🥱 😴 🤤 😪 😵 ' '️😣 😖 😫 😩 🥺 😢 😭 😤 😠 😡 🤬 🤯 😳 🥵 🥶 😱 😨 😰 😥 😓 '
'🤐 🥴 🤢 🤮 🤧 😷 🤒 🤕 🤑 🤠 😈 👿 👹 👺 🤡 💩 👻 💀 ☠️ 👽 ' '🤗 🤔 🤭 🤫 🤥 😶 😐 😑 😬 🙄 😯 😦 😧 😮 😲 🥱 😴 🤤 😪 😵 '
'👾 🤖 🎃 😺 😸 😹 😻 😼 😽 🙀 😿 😾 ' '🤐 🥴 🤢 🤮 🤧 😷 🤒 🤕 🤑 🤠 😈 👿 👹 👺 🤡 💩 👻 💀 ☠️ 👽 '
'👋 🤚 🖐 ✋ 🖖 👌 🤌 🤏 ✌️ 🤞 🤟 🤘 🤙 👈 👉 👆 🖕 👇 ☝️ 👍 👎 ' '👾 🤖 🎃 😺 😸 😹 😻 😼 😽 🙀 😿 😾 '
'✊ 👊 🤛 🤜 👏 🙌 👐 🤲 🤝 🙏 ✍️ 💅 🤳 💪 🦾 🦵 🦿 🦶 👣 👂 ' '👋 🤚 🖐 ✋ 🖖 👌 🤌 🤏 ✌️ 🤞 🤟 🤘 🤙 👈 👉 👆 🖕 👇 ☝️ 👍 👎 '
'🦻 👃 🫀 🫁 🧠 🦷 🦴 👀 👁 👅 👄 💋 🩸'; '✊ 👊 🤛 🤜 👏 🙌 👐 🤲 🤝 🙏 ✍️ 💅 🤳 💪 🦾 🦵 🦿 🦶 👣 👂 '
'🦻 👃 🫀 🫁 🧠 🦷 🦴 👀 👁 👅 👄 💋 🩸';
class TextFieldPage extends StatelessWidget { class TextFieldPage extends StatelessWidget {
const TextFieldPage({super.key}); const TextFieldPage({super.key});

View File

@ -11,7 +11,8 @@ import '../common.dart';
Map<String, WidgetBuilder> gradientPerfRoutes = <String, WidgetBuilder>{ Map<String, WidgetBuilder> gradientPerfRoutes = <String, WidgetBuilder>{
kGradientPerfRecreateDynamicRouteName: (BuildContext _) => const RecreateDynamicPainterPage(), kGradientPerfRecreateDynamicRouteName: (BuildContext _) => const RecreateDynamicPainterPage(),
kGradientPerfRecreateConsistentRouteName: (BuildContext _) => const RecreateConsistentPainterPage(), kGradientPerfRecreateConsistentRouteName:
(BuildContext _) => const RecreateConsistentPainterPage(),
kGradientPerfStaticConsistentRouteName: (BuildContext _) => const StaticConsistentPainterPage(), kGradientPerfStaticConsistentRouteName: (BuildContext _) => const StaticConsistentPainterPage(),
}; };
@ -66,7 +67,7 @@ class _PainterPage extends StatefulWidget {
class RecreateDynamicPainterPage extends _PainterPage { class RecreateDynamicPainterPage extends _PainterPage {
const RecreateDynamicPainterPage({super.key}) const RecreateDynamicPainterPage({super.key})
: super(title: 'Recreate Dynamic Gradients', factory: makePainter); : super(title: 'Recreate Dynamic Gradients', factory: makePainter);
static CustomPainter makePainter(double f) { static CustomPainter makePainter(double f) {
return RecreatedDynamicGradients(baseFactor: f); return RecreatedDynamicGradients(baseFactor: f);
@ -75,7 +76,7 @@ class RecreateDynamicPainterPage extends _PainterPage {
class RecreateConsistentPainterPage extends _PainterPage { class RecreateConsistentPainterPage extends _PainterPage {
const RecreateConsistentPainterPage({super.key}) const RecreateConsistentPainterPage({super.key})
: super(title: 'Recreate Same Gradients', factory: makePainter); : super(title: 'Recreate Same Gradients', factory: makePainter);
static CustomPainter makePainter(double f) { static CustomPainter makePainter(double f) {
return RecreatedConsistentGradients(baseFactor: f); return RecreatedConsistentGradients(baseFactor: f);
@ -84,7 +85,7 @@ class RecreateConsistentPainterPage extends _PainterPage {
class StaticConsistentPainterPage extends _PainterPage { class StaticConsistentPainterPage extends _PainterPage {
const StaticConsistentPainterPage({super.key}) const StaticConsistentPainterPage({super.key})
: super(title: 'Reuse Same Gradients', factory: makePainter); : super(title: 'Reuse Same Gradients', factory: makePainter);
static CustomPainter makePainter(double f) { static CustomPainter makePainter(double f) {
return StaticConsistentGradients(baseFactor: f); return StaticConsistentGradients(baseFactor: f);
@ -110,9 +111,7 @@ class _PainterPageState extends State<_PainterPage> with SingleTickerProviderSta
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
return Scaffold( return Scaffold(
appBar: AppBar( appBar: AppBar(title: Text(widget.title)),
title: Text(widget.title),
),
body: Center( body: Center(
child: AnimatedBuilder( child: AnimatedBuilder(
animation: _controller, animation: _controller,
@ -155,16 +154,13 @@ Color color(double factor) {
} }
Shader rotatingGradient(double factor, double x, double y, double h) { Shader rotatingGradient(double factor, double x, double y, double h) {
final double s = sin(factor * 2 * pi) * h/8; final double s = sin(factor * 2 * pi) * h / 8;
final double c = cos(factor * 2 * pi) * h/8; final double c = cos(factor * 2 * pi) * h / 8;
final double cx = x; final double cx = x;
final double cy = y + h/2; final double cy = y + h / 2;
final Offset p0 = Offset(cx + s, cy + c); final Offset p0 = Offset(cx + s, cy + c);
final Offset p1 = Offset(cx - s, cy - c); final Offset p1 = Offset(cx - s, cy - c);
return ui.Gradient.linear(p0, p1, <Color>[ return ui.Gradient.linear(p0, p1, <Color>[color(factor), color(factor + 0.5)]);
color(factor),
color(factor + 0.5),
]);
} }
const int nAcross = 12; const int nAcross = 12;
@ -185,8 +181,8 @@ double y(int i, int j) {
} }
Shader gradient(double baseFactor, int i, int j) { Shader gradient(double baseFactor, int i, int j) {
final double lineFactor = baseFactor + 1/3 + 0.5 * (j + 1) / (nDown + 1); final double lineFactor = baseFactor + 1 / 3 + 0.5 * (j + 1) / (nDown + 1);
final double cellFactor = lineFactor + 1/3 * (i + 1) / (nAcross + 1); final double cellFactor = lineFactor + 1 / 3 * (i + 1) / (nAcross + 1);
return rotatingGradient(cellFactor, x(i, j) + cellW / 2, y(i, j), cellH); return rotatingGradient(cellFactor, x(i, j) + cellW / 2, y(i, j), cellH);
} }
@ -240,11 +236,7 @@ class StaticConsistentGradients extends CustomPainter {
final double baseFactor; final double baseFactor;
static List<List<Shader>> gradients = <List<Shader>>[ static List<List<Shader>> gradients = <List<Shader>>[
for (int j = 0; j < nDown; j++) for (int j = 0; j < nDown; j++) <Shader>[for (int i = 0; i < nAcross; i++) gradient(0, i, j)],
<Shader>[
for (int i = 0; i < nAcross; i++)
gradient(0, i, j),
],
]; ];
@override @override

View File

@ -25,10 +25,6 @@ class HeavyWidget extends StatelessWidget {
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
return SizedBox( return SizedBox(width: 200, height: 200, child: Text('$index: ${_weight.length}'));
width: 200,
height: 200,
child: Text('$index: ${_weight.length}'),
);
} }
} }

View File

@ -18,21 +18,19 @@ class ColumnOfTextState extends State<ColumnOfText> with SingleTickerProviderSta
@override @override
void initState() { void initState() {
super.initState(); super.initState();
_controller = AnimationController( _controller =
vsync: this, AnimationController(vsync: this, duration: const Duration(milliseconds: 300))
duration: const Duration(milliseconds: 300), ..addStatusListener((AnimationStatus status) {
) if (status.isCompleted) {
..addStatusListener((AnimationStatus status) { setState(() {
if (status.isCompleted) { _showText = !_showText;
setState(() { });
_showText = !_showText; _controller
}); ..reset()
_controller ..forward();
..reset() }
..forward(); })
} ..forward();
})
..forward();
} }
@override @override
@ -47,22 +45,21 @@ class ColumnOfTextState extends State<ColumnOfText> with SingleTickerProviderSta
child: OverflowBox( child: OverflowBox(
alignment: Alignment.topCenter, alignment: Alignment.topCenter,
maxHeight: double.infinity, maxHeight: double.infinity,
child: !_showText child:
? Container() !_showText
: Column( ? Container()
children: List<Widget>.generate(9, (int index) { : Column(
return ListTile( children: List<Widget>.generate(9, (int index) {
leading: CircleAvatar( return ListTile(
child: Text('G$index'), leading: CircleAvatar(child: Text('G$index')),
), title: Text(
title: Text( 'Foo contact from $index-th local contact',
'Foo contact from $index-th local contact', overflow: TextOverflow.ellipsis,
overflow: TextOverflow.ellipsis, ),
), subtitle: Text('+91 88888 8800$index'),
subtitle: Text('+91 88888 8800$index'), );
); }),
}), ),
),
), ),
); );
} }

View File

@ -17,9 +17,21 @@ class MultiWidgetConstructTable extends StatefulWidget {
class _MultiWidgetConstructTableState extends State<MultiWidgetConstructTable> class _MultiWidgetConstructTableState extends State<MultiWidgetConstructTable>
with SingleTickerProviderStateMixin { with SingleTickerProviderStateMixin {
static const List<MaterialColor> colorList = <MaterialColor>[ static const List<MaterialColor> colorList = <MaterialColor>[
Colors.pink, Colors.red, Colors.deepOrange, Colors.orange, Colors.amber, Colors.pink,
Colors.yellow, Colors.lime, Colors.lightGreen, Colors.green, Colors.teal, Colors.red,
Colors.cyan, Colors.lightBlue, Colors.blue, Colors.indigo, Colors.purple, Colors.deepOrange,
Colors.orange,
Colors.amber,
Colors.yellow,
Colors.lime,
Colors.lightGreen,
Colors.green,
Colors.teal,
Colors.cyan,
Colors.lightBlue,
Colors.blue,
Colors.indigo,
Colors.purple,
]; ];
int counter = 0; int counter = 0;
@ -60,32 +72,27 @@ class _MultiWidgetConstructTableState extends State<MultiWidgetConstructTable>
children: List<TableRow>.generate( children: List<TableRow>.generate(
widget.rowCount, widget.rowCount,
(int row) => TableRow( (int row) => TableRow(
children: List<Widget>.generate( children: List<Widget>.generate(widget.columnCount, (int column) {
widget.columnCount, final int label = row * widget.columnCount + column;
(int column) { // This implementation rebuild the widget tree for every
final int label = row * widget.columnCount + column; // frame, and is intentionally designed of poor performance
// This implementation rebuild the widget tree for every // for benchmark purposes.
// frame, and is intentionally designed of poor performance return counter.isEven
// for benchmark purposes. ? Container(
return counter.isEven // This key forces rebuilding the element
? Container( key: ValueKey<int>(widgetCounter + label),
// This key forces rebuilding the element color: Color.lerp(Colors.white, baseColor, label / totalLength),
key: ValueKey<int>(widgetCounter + label), constraints: BoxConstraints.expand(height: height),
color: Color.lerp( child: Text('${widgetCounter + label}'),
Colors.white, baseColor, label / totalLength), )
constraints: BoxConstraints.expand(height: height), : MyContainer(
child: Text('${widgetCounter + label}'), // This key forces rebuilding the element
) key: ValueKey<int>(widgetCounter + label),
: MyContainer( color: Color.lerp(Colors.white, baseColor, label / totalLength)!,
// This key forces rebuilding the element constraints: BoxConstraints.expand(height: height),
key: ValueKey<int>(widgetCounter + label), child: Text('${widgetCounter + label}'),
color: Color.lerp( );
Colors.white, baseColor, label / totalLength)!, }),
constraints: BoxConstraints.expand(height: height),
child: Text('${widgetCounter + label}'),
);
},
),
), ),
), ),
), ),
@ -97,17 +104,18 @@ class _MultiWidgetConstructTableState extends State<MultiWidgetConstructTable>
// This class is intended to break the original Widget tree // This class is intended to break the original Widget tree
class MyContainer extends StatelessWidget { class MyContainer extends StatelessWidget {
const MyContainer({required this.color, required this.child, required this.constraints, super.key}); const MyContainer({
required this.color,
required this.child,
required this.constraints,
super.key,
});
final Color color; final Color color;
final Widget child; final Widget child;
final BoxConstraints constraints; final BoxConstraints constraints;
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
return Container( return Container(color: color, constraints: constraints, child: child);
color: color,
constraints: constraints,
child: child,
);
} }
} }

View File

@ -44,18 +44,25 @@ int _green(double v) => _red(1 - v);
int _blue(double v) => 0; int _blue(double v) => 0;
class OpacityPeepholeCase { class OpacityPeepholeCase {
OpacityPeepholeCase.forValue({required String route, required String name, required ValueBuilder builder}) OpacityPeepholeCase.forValue({
: this.forAnimation( required String route,
route: route, required String name,
name: name, required ValueBuilder builder,
builder: (Animation<double> animation) => AnimatedBuilder( }) : this.forAnimation(
animation: animation, route: route,
builder: (BuildContext context, Widget? child) => builder(animation.value), name: name,
), builder:
); (Animation<double> animation) => AnimatedBuilder(
animation: animation,
builder: (BuildContext context, Widget? child) => builder(animation.value),
),
);
OpacityPeepholeCase.forAnimation({required this.route, required this.name, required AnimationBuilder builder}) OpacityPeepholeCase.forAnimation({
: animationBuilder = builder; required this.route,
required this.name,
required AnimationBuilder builder,
}) : animationBuilder = builder;
final String route; final String route;
final String name; final String name;
@ -80,7 +87,7 @@ List<OpacityPeepholeCase> allOpacityPeepholeCases = <OpacityPeepholeCase>[
color: Color.fromARGB(255, _red(v), _green(v), _blue(v)), color: Color.fromARGB(255, _red(v), _green(v), _blue(v)),
), ),
); );
} },
), ),
// Tests that a column of Opacity widgets can individually hand their values down to simple children // Tests that a column of Opacity widgets can individually hand their values down to simple children
OpacityPeepholeCase.forValue( OpacityPeepholeCase.forValue(
@ -108,32 +115,32 @@ List<OpacityPeepholeCase> allOpacityPeepholeCases = <OpacityPeepholeCase>[
), ),
// Tests that an Opacity can hand value down to a cached child // Tests that an Opacity can hand value down to a cached child
OpacityPeepholeCase.forValue( OpacityPeepholeCase.forValue(
route: kOpacityPeepholeOpacityOfCachedChildRouteName, route: kOpacityPeepholeOpacityOfCachedChildRouteName,
name: 'Opacity of Cached Child', name: 'Opacity of Cached Child',
builder: (double v) { builder: (double v) {
// ChildV starts as a constant so the same color pattern always appears and the child will be cached // ChildV starts as a constant so the same color pattern always appears and the child will be cached
double childV = 0; double childV = 0;
return Opacity( return Opacity(
opacity: _opacity(v), opacity: _opacity(v),
child: RepaintBoundary( child: RepaintBoundary(
child: SizedBox( child: SizedBox(
width: 300, width: 300,
height: 400, height: 400,
child: Stack( child: Stack(
children: <Widget>[ children: <Widget>[
for (double i = 0; i < 100; i += 10, childV = 1 - childV) for (double i = 0; i < 100; i += 10, childV = 1 - childV)
Positioned.fromRelativeRect( Positioned.fromRelativeRect(
rect: RelativeRect.fromLTRB(i, i, i, i), rect: RelativeRect.fromLTRB(i, i, i, i),
child: Container( child: Container(
color: Color.fromARGB(255, _red(childV), _green(childV), _blue(childV)), color: Color.fromARGB(255, _red(childV), _green(childV), _blue(childV)),
),
), ),
], ),
), ],
), ),
), ),
); ),
} );
},
), ),
// Tests that an Opacity can hand a value down to a Column of simple non-overlapping children // Tests that an Opacity can hand a value down to a Column of simple non-overlapping children
OpacityPeepholeCase.forValue( OpacityPeepholeCase.forValue(
@ -277,11 +284,7 @@ List<OpacityPeepholeCase> allOpacityPeepholeCases = <OpacityPeepholeCase>[
child: const SizedBox( child: const SizedBox(
width: 300, width: 300,
height: 400, height: 400,
child: Center( child: Center(child: Text('Hello, World', style: TextStyle(fontSize: 48))),
child: Text('Hello, World',
style: TextStyle(fontSize: 48),
),
),
), ),
); );
}, },
@ -414,8 +417,7 @@ class RectGridPainter extends CustomPainter {
} }
Map<String, WidgetBuilder> opacityPeepholeRoutes = <String, WidgetBuilder>{ Map<String, WidgetBuilder> opacityPeepholeRoutes = <String, WidgetBuilder>{
for (OpacityPeepholeCase variant in allOpacityPeepholeCases) for (OpacityPeepholeCase variant in allOpacityPeepholeCases) variant.route: variant.buildPage,
variant.route: variant.buildPage,
}; };
class VariantPage extends StatefulWidget { class VariantPage extends StatefulWidget {
@ -448,12 +450,8 @@ class VariantPageState extends State<VariantPage> with SingleTickerProviderState
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
return Scaffold( return Scaffold(
appBar: AppBar( appBar: AppBar(title: Text(widget.variant.name)),
title: Text(widget.variant.name), body: Center(child: widget.variant.animationBuilder(_controller)),
),
body: Center(
child: widget.variant.animationBuilder(_controller),
),
); );
} }
} }

View File

@ -18,8 +18,7 @@ class _PathTessellationPageState extends State<PathTessellationPage>
@override @override
void initState() { void initState() {
super.initState(); super.initState();
_controller = _controller = AnimationController(vsync: this, lowerBound: 1.0, upperBound: 1.3);
AnimationController(vsync: this, lowerBound: 1.0, upperBound: 1.3);
_controller.addListener(() { _controller.addListener(() {
setState(() {}); setState(() {});
}); });
@ -35,14 +34,11 @@ class _PathTessellationPageState extends State<PathTessellationPage>
fit: StackFit.expand, fit: StackFit.expand,
children: <Widget>[ children: <Widget>[
ListView.builder( ListView.builder(
key: const Key( key: const Key('list_view'), // this key is used by the driver test,
'list_view'), // this key is used by the driver test,
itemBuilder: (BuildContext context, int index) { itemBuilder: (BuildContext context, int index) {
return Container( return Container(
margin: const EdgeInsets.all(1.0), margin: const EdgeInsets.all(1.0),
decoration: BoxDecoration( decoration: BoxDecoration(color: Colors.white.withOpacity(0.2)),
color: Colors.white.withOpacity(0.2),
),
child: IconRow(iconSize: (30 + 0.5 * (index % 10)) * scale), child: IconRow(iconSize: (30 + 0.5 * (index % 10)) * scale),
); );
}, },
@ -68,23 +64,16 @@ class _PathTessellationPageState extends State<PathTessellationPage>
child: Column( child: Column(
crossAxisAlignment: CrossAxisAlignment.stretch, crossAxisAlignment: CrossAxisAlignment.stretch,
children: <Widget>[ children: <Widget>[
SizedBox( SizedBox(height: 100, child: IconRow(iconSize: 55.0 * scale)),
height: 100,
child: IconRow(iconSize: 55.0 * scale),
),
MaterialButton( MaterialButton(
textColor: Colors.white, textColor: Colors.white,
key: const Key( key: const Key('animate_button'), // this key is used by the driver test
'animate_button'), // this key is used by the driver test
child: const Text('Animate'), child: const Text('Animate'),
onPressed: () { onPressed: () {
if (_controller.isAnimating) { if (_controller.isAnimating) {
_controller.stop(); _controller.stop();
} else { } else {
_controller.repeat( _controller.repeat(period: const Duration(seconds: 1), reverse: true);
period: const Duration(seconds: 1),
reverse: true,
);
} }
}, },
), ),
@ -100,10 +89,7 @@ class _PathTessellationPageState extends State<PathTessellationPage>
} }
class IconRow extends StatelessWidget { class IconRow extends StatelessWidget {
const IconRow({ const IconRow({super.key, required this.iconSize});
super.key,
required this.iconSize,
});
final double iconSize; final double iconSize;
@ -114,38 +100,23 @@ class IconRow extends StatelessWidget {
children: <Widget>[ children: <Widget>[
SizedBox.square( SizedBox.square(
dimension: iconSize, dimension: iconSize,
child: CustomPaint( child: CustomPaint(painter: _SettingsIconPainter(), willChange: true),
painter: _SettingsIconPainter(),
willChange: true,
),
), ),
SizedBox.square( SizedBox.square(
dimension: iconSize, dimension: iconSize,
child: CustomPaint( child: CustomPaint(painter: _CameraIconPainter(), willChange: true),
painter: _CameraIconPainter(),
willChange: true,
),
), ),
SizedBox.square( SizedBox.square(
dimension: iconSize, dimension: iconSize,
child: CustomPaint( child: CustomPaint(painter: _CalendarIconPainter(), willChange: true),
painter: _CalendarIconPainter(),
willChange: true,
),
), ),
SizedBox.square( SizedBox.square(
dimension: iconSize, dimension: iconSize,
child: CustomPaint( child: CustomPaint(painter: _ConversationIconPainter(), willChange: true),
painter: _ConversationIconPainter(),
willChange: true,
),
), ),
SizedBox.square( SizedBox.square(
dimension: iconSize, dimension: iconSize,
child: CustomPaint( child: CustomPaint(painter: _GeometryIconPainter(), willChange: true),
painter: _GeometryIconPainter(),
willChange: true,
),
), ),
], ],
); );
@ -175,8 +146,14 @@ Path _pathFromString(String pathString) {
path.lineTo(arguments[0], arguments[1]); path.lineTo(arguments[0], arguments[1]);
current = Offset(arguments[0], arguments[1]); current = Offset(arguments[0], arguments[1]);
case 'C': case 'C':
path.cubicTo(arguments[0], arguments[1], arguments[2], arguments[3], path.cubicTo(
arguments[4], arguments[5]); arguments[0],
arguments[1],
arguments[2],
arguments[3],
arguments[4],
arguments[5],
);
current = Offset(arguments[4], arguments[5]); current = Offset(arguments[4], arguments[5]);
case 'H': case 'H':
path.lineTo(arguments[0], current.dy); path.lineTo(arguments[0], current.dy);
@ -206,8 +183,7 @@ Path _pathFromString(String pathString) {
class _SettingsIconPainter extends CustomPainter { class _SettingsIconPainter extends CustomPainter {
@override @override
void paint(Canvas canvas, Size size) { void paint(Canvas canvas, Size size) {
final Matrix4 scale = final Matrix4 scale = Matrix4.diagonal3Values(size.width / 20, size.height / 20, 1.0);
Matrix4.diagonal3Values(size.width / 20, size.height / 20, 1.0);
Path path; Path path;
path = _path1.transform(scale.storage)..fillType = PathFillType.evenOdd; path = _path1.transform(scale.storage)..fillType = PathFillType.evenOdd;
@ -221,11 +197,14 @@ class _SettingsIconPainter extends CustomPainter {
} }
static final Path _path1 = _pathFromString( static final Path _path1 = _pathFromString(
'M8.3252 2.675L7.7877 4.0625L5.93771 5.1125L4.4627 4.8875C4.2171 4.85416 3.96713 4.89459 3.74456 5.00365C3.52199 5.11271 3.33686 5.28548 3.21271 5.5L2.7127 6.375C2.58458 6.59294 2.52555 6.8446 2.5434 7.09678C2.56126 7.34895 2.65516 7.58979 2.8127 7.7875L3.7502 8.95V11.05L2.8377 12.2125C2.68016 12.4102 2.58626 12.651 2.5684 12.9032C2.55055 13.1554 2.60958 13.4071 2.73771 13.625L3.2377 14.5C3.36186 14.7145 3.54699 14.8873 3.76956 14.9963C3.99213 15.1054 4.2421 15.1458 4.4877 15.1125L5.96271 14.8875L7.7877 15.9375L8.3252 17.325C8.41585 17.5599 8.57534 17.762 8.78277 17.9047C8.9902 18.0475 9.2359 18.1243 9.48771 18.125H10.5377C10.7895 18.1243 11.0352 18.0475 11.2426 17.9047C11.4501 17.762 11.6096 17.5599 11.7002 17.325L12.2377 15.9375L14.0627 14.8875L15.5377 15.1125C15.7833 15.1458 16.0333 15.1054 16.2559 14.9963C16.4784 14.8873 16.6636 14.7145 16.7877 14.5L17.2877 13.625C17.4158 13.4071 17.4749 13.1554 17.457 12.9032C17.4392 12.651 17.3453 12.4102 17.1877 12.2125L16.2502 11.05V8.95L17.1627 7.7875C17.3203 7.58979 17.4142 7.34895 17.432 7.09678C17.4499 6.8446 17.3908 6.59294 17.2627 6.375L16.7627 5.5C16.6386 5.28548 16.4534 5.11271 16.2309 5.00365C16.0083 4.89459 15.7583 4.85416 15.5127 4.8875L14.0377 5.1125L12.2127 4.0625L11.6752 2.675C11.5846 2.44008 11.4251 2.23801 11.2176 2.09527C11.0102 1.95252 10.7645 1.87574 10.5127 1.875H9.48771C9.2359 1.87574 8.9902 1.95252 8.78277 2.09527C8.57534 2.23801 8.41585 2.44008 8.3252 2.675ZM10 12.5C11.3807 12.5 12.5 11.3807 12.5 10C12.5 8.61929 11.3807 7.5 10 7.5C8.61929 7.5 7.5 8.61929 7.5 10C7.5 11.3807 8.61929 12.5 10 12.5Z'); 'M8.3252 2.675L7.7877 4.0625L5.93771 5.1125L4.4627 4.8875C4.2171 4.85416 3.96713 4.89459 3.74456 5.00365C3.52199 5.11271 3.33686 5.28548 3.21271 5.5L2.7127 6.375C2.58458 6.59294 2.52555 6.8446 2.5434 7.09678C2.56126 7.34895 2.65516 7.58979 2.8127 7.7875L3.7502 8.95V11.05L2.8377 12.2125C2.68016 12.4102 2.58626 12.651 2.5684 12.9032C2.55055 13.1554 2.60958 13.4071 2.73771 13.625L3.2377 14.5C3.36186 14.7145 3.54699 14.8873 3.76956 14.9963C3.99213 15.1054 4.2421 15.1458 4.4877 15.1125L5.96271 14.8875L7.7877 15.9375L8.3252 17.325C8.41585 17.5599 8.57534 17.762 8.78277 17.9047C8.9902 18.0475 9.2359 18.1243 9.48771 18.125H10.5377C10.7895 18.1243 11.0352 18.0475 11.2426 17.9047C11.4501 17.762 11.6096 17.5599 11.7002 17.325L12.2377 15.9375L14.0627 14.8875L15.5377 15.1125C15.7833 15.1458 16.0333 15.1054 16.2559 14.9963C16.4784 14.8873 16.6636 14.7145 16.7877 14.5L17.2877 13.625C17.4158 13.4071 17.4749 13.1554 17.457 12.9032C17.4392 12.651 17.3453 12.4102 17.1877 12.2125L16.2502 11.05V8.95L17.1627 7.7875C17.3203 7.58979 17.4142 7.34895 17.432 7.09678C17.4499 6.8446 17.3908 6.59294 17.2627 6.375L16.7627 5.5C16.6386 5.28548 16.4534 5.11271 16.2309 5.00365C16.0083 4.89459 15.7583 4.85416 15.5127 4.8875L14.0377 5.1125L12.2127 4.0625L11.6752 2.675C11.5846 2.44008 11.4251 2.23801 11.2176 2.09527C11.0102 1.95252 10.7645 1.87574 10.5127 1.875H9.48771C9.2359 1.87574 8.9902 1.95252 8.78277 2.09527C8.57534 2.23801 8.41585 2.44008 8.3252 2.675ZM10 12.5C11.3807 12.5 12.5 11.3807 12.5 10C12.5 8.61929 11.3807 7.5 10 7.5C8.61929 7.5 7.5 8.61929 7.5 10C7.5 11.3807 8.61929 12.5 10 12.5Z',
);
static final Path _path2 = _pathFromString( static final Path _path2 = _pathFromString(
'M9.48771 1.25L9.48586 1.25001C9.10816 1.25112 8.7396 1.36628 8.42845 1.5804C8.11747 1.79441 7.87833 2.0973 7.74232 2.44945L7.2854 3.62894L5.81769 4.46197L4.55695 4.26965L4.54677 4.26818C4.17836 4.21818 3.80341 4.27882 3.46955 4.44241C3.13569 4.606 2.858 4.86515 2.67177 5.18693L2.17177 6.06191C1.98107 6.38797 1.89329 6.76406 1.91997 7.14092C1.94675 7.51918 2.08759 7.88043 2.32392 8.177L3.12521 9.17062V10.834L2.34736 11.825C2.11197 12.1212 1.97169 12.4817 1.94497 12.8591C1.91828 13.236 2.00608 13.6121 2.1968 13.9381L2.69505 14.8101L2.69677 14.8131C2.883 15.1349 3.16069 15.394 3.49455 15.5576C3.82841 15.7212 4.20336 15.7818 4.57177 15.7318L5.84067 15.5383L7.28466 16.3691L7.28539 16.3711L7.74211 17.55C7.87812 17.9021 8.11745 18.2056 8.42843 18.4196C8.73958 18.6337 9.10814 18.7489 9.48584 18.75L9.48769 18.75L10.5145 18.75C10.8922 18.7489 11.2608 18.6337 11.5719 18.4196C11.8829 18.2056 12.1473 17.9021 12.2833 17.55L12.7408 16.3691L14.1847 15.5383L15.4434 15.7304L15.4536 15.7318C15.822 15.7818 16.197 15.7212 16.5309 15.5576C16.8647 15.394 17.1424 15.1349 17.3286 14.8131L17.3304 14.8101L17.8287 13.9381C18.0193 13.612 18.1071 13.2359 18.0804 12.8591C18.0537 12.4808 17.9128 12.1196 17.6765 11.823L16.8752 10.8294V9.166L17.6515 8.177L17.6531 8.17502C17.8884 7.87883 18.0287 7.51834 18.0554 7.14092C18.0821 6.76407 17.9943 6.38798 17.8036 6.06192L17.3054 5.18991L17.3036 5.18693C17.1174 4.86515 16.8397 4.606 16.5059 4.44241C16.172 4.27882 15.797 4.21809 15.4286 4.2681L14.1597 4.46166L12.7158 3.63087L12.258 2.44923C12.122 2.09718 11.8829 1.79437 11.572 1.5804C11.2608 1.36628 10.8923 1.25112 10.5146 1.25L9.48771 1.25ZM10.5116 2.5H9.48879C9.36315 2.50053 9.24059 2.5389 9.13708 2.61013C9.03337 2.68151 8.95363 2.78254 8.9083 2.9L8.3705 4.28827C8.31845 4.42266 8.22154 4.53492 8.09621 4.60606L6.24621 5.65606C6.12411 5.72535 5.98224 5.75153 5.84346 5.73036L4.37442 5.50627C4.25298 5.49062 4.12958 5.51099 4.01957 5.5649C3.90871 5.61922 3.81643 5.70515 3.75436 5.81183L3.25154 6.69178C3.18747 6.80075 3.15792 6.92655 3.16684 7.05264C3.17574 7.17824 3.22235 7.2982 3.30057 7.39684L4.23671 8.55766C4.32633 8.66878 4.37521 8.80724 4.37521 8.95V11.05C4.37521 11.1899 4.32824 11.3258 4.24184 11.4359L3.32651 12.602C3.24773 12.7009 3.20077 12.8213 3.19184 12.9474C3.18292 13.0735 3.21243 13.1993 3.27649 13.3083L3.2804 13.3149L3.77864 14.1869L3.77933 14.1881C3.8414 14.2948 3.93369 14.3808 4.04457 14.4351C4.15457 14.489 4.27796 14.5094 4.39939 14.4937L5.86846 14.2696C6.00848 14.2483 6.15161 14.2751 6.27439 14.3458L8.09939 15.3958C8.22322 15.467 8.3189 15.5785 8.3705 15.7117L8.908 17.0992C8.95333 17.2167 9.03337 17.3185 9.13708 17.3899C9.24061 17.4611 9.36321 17.4995 9.48887 17.5H10.5365C10.6622 17.4995 10.7848 17.4611 10.8883 17.3899C10.992 17.3185 11.0718 17.2175 11.1171 17.1L11.6549 15.7117C11.7065 15.5785 11.8022 15.467 11.926 15.3958L13.751 14.3458C13.8738 14.2751 14.0169 14.2483 14.157 14.2696L15.626 14.4937C15.7475 14.5094 15.8708 14.489 15.9808 14.4351C16.0917 14.3808 16.184 14.2949 16.2461 14.1882L16.2468 14.1869L16.7489 13.3082C16.8129 13.1993 16.8425 13.0735 16.8336 12.9474C16.8247 12.8218 16.7781 12.7019 16.6999 12.6032L16.6989 12.602L15.7637 11.4423C15.6741 11.3312 15.6252 11.1928 15.6252 11.05V8.95C15.6252 8.81006 15.6722 8.67418 15.7586 8.5641L16.6711 7.4016L16.6739 7.398C16.7527 7.29915 16.7996 7.17873 16.8086 7.05264C16.8175 6.92655 16.788 6.80072 16.7239 6.69175L16.72 6.68511L16.2218 5.81307L16.2211 5.81187C16.159 5.70517 16.0667 5.61923 15.9558 5.5649C15.8458 5.51099 15.7224 5.49062 15.601 5.50627L14.132 5.73036C13.9919 5.75172 13.8488 5.72488 13.726 5.65424L11.901 4.60424C11.7772 4.533 11.6815 4.42148 11.6299 4.28827L11.0924 2.90077C11.0471 2.78331 10.967 2.68151 10.8633 2.61013C10.7598 2.5389 10.6373 2.50053 10.5116 2.5Z'); 'M9.48771 1.25L9.48586 1.25001C9.10816 1.25112 8.7396 1.36628 8.42845 1.5804C8.11747 1.79441 7.87833 2.0973 7.74232 2.44945L7.2854 3.62894L5.81769 4.46197L4.55695 4.26965L4.54677 4.26818C4.17836 4.21818 3.80341 4.27882 3.46955 4.44241C3.13569 4.606 2.858 4.86515 2.67177 5.18693L2.17177 6.06191C1.98107 6.38797 1.89329 6.76406 1.91997 7.14092C1.94675 7.51918 2.08759 7.88043 2.32392 8.177L3.12521 9.17062V10.834L2.34736 11.825C2.11197 12.1212 1.97169 12.4817 1.94497 12.8591C1.91828 13.236 2.00608 13.6121 2.1968 13.9381L2.69505 14.8101L2.69677 14.8131C2.883 15.1349 3.16069 15.394 3.49455 15.5576C3.82841 15.7212 4.20336 15.7818 4.57177 15.7318L5.84067 15.5383L7.28466 16.3691L7.28539 16.3711L7.74211 17.55C7.87812 17.9021 8.11745 18.2056 8.42843 18.4196C8.73958 18.6337 9.10814 18.7489 9.48584 18.75L9.48769 18.75L10.5145 18.75C10.8922 18.7489 11.2608 18.6337 11.5719 18.4196C11.8829 18.2056 12.1473 17.9021 12.2833 17.55L12.7408 16.3691L14.1847 15.5383L15.4434 15.7304L15.4536 15.7318C15.822 15.7818 16.197 15.7212 16.5309 15.5576C16.8647 15.394 17.1424 15.1349 17.3286 14.8131L17.3304 14.8101L17.8287 13.9381C18.0193 13.612 18.1071 13.2359 18.0804 12.8591C18.0537 12.4808 17.9128 12.1196 17.6765 11.823L16.8752 10.8294V9.166L17.6515 8.177L17.6531 8.17502C17.8884 7.87883 18.0287 7.51834 18.0554 7.14092C18.0821 6.76407 17.9943 6.38798 17.8036 6.06192L17.3054 5.18991L17.3036 5.18693C17.1174 4.86515 16.8397 4.606 16.5059 4.44241C16.172 4.27882 15.797 4.21809 15.4286 4.2681L14.1597 4.46166L12.7158 3.63087L12.258 2.44923C12.122 2.09718 11.8829 1.79437 11.572 1.5804C11.2608 1.36628 10.8923 1.25112 10.5146 1.25L9.48771 1.25ZM10.5116 2.5H9.48879C9.36315 2.50053 9.24059 2.5389 9.13708 2.61013C9.03337 2.68151 8.95363 2.78254 8.9083 2.9L8.3705 4.28827C8.31845 4.42266 8.22154 4.53492 8.09621 4.60606L6.24621 5.65606C6.12411 5.72535 5.98224 5.75153 5.84346 5.73036L4.37442 5.50627C4.25298 5.49062 4.12958 5.51099 4.01957 5.5649C3.90871 5.61922 3.81643 5.70515 3.75436 5.81183L3.25154 6.69178C3.18747 6.80075 3.15792 6.92655 3.16684 7.05264C3.17574 7.17824 3.22235 7.2982 3.30057 7.39684L4.23671 8.55766C4.32633 8.66878 4.37521 8.80724 4.37521 8.95V11.05C4.37521 11.1899 4.32824 11.3258 4.24184 11.4359L3.32651 12.602C3.24773 12.7009 3.20077 12.8213 3.19184 12.9474C3.18292 13.0735 3.21243 13.1993 3.27649 13.3083L3.2804 13.3149L3.77864 14.1869L3.77933 14.1881C3.8414 14.2948 3.93369 14.3808 4.04457 14.4351C4.15457 14.489 4.27796 14.5094 4.39939 14.4937L5.86846 14.2696C6.00848 14.2483 6.15161 14.2751 6.27439 14.3458L8.09939 15.3958C8.22322 15.467 8.3189 15.5785 8.3705 15.7117L8.908 17.0992C8.95333 17.2167 9.03337 17.3185 9.13708 17.3899C9.24061 17.4611 9.36321 17.4995 9.48887 17.5H10.5365C10.6622 17.4995 10.7848 17.4611 10.8883 17.3899C10.992 17.3185 11.0718 17.2175 11.1171 17.1L11.6549 15.7117C11.7065 15.5785 11.8022 15.467 11.926 15.3958L13.751 14.3458C13.8738 14.2751 14.0169 14.2483 14.157 14.2696L15.626 14.4937C15.7475 14.5094 15.8708 14.489 15.9808 14.4351C16.0917 14.3808 16.184 14.2949 16.2461 14.1882L16.2468 14.1869L16.7489 13.3082C16.8129 13.1993 16.8425 13.0735 16.8336 12.9474C16.8247 12.8218 16.7781 12.7019 16.6999 12.6032L16.6989 12.602L15.7637 11.4423C15.6741 11.3312 15.6252 11.1928 15.6252 11.05V8.95C15.6252 8.81006 15.6722 8.67418 15.7586 8.5641L16.6711 7.4016L16.6739 7.398C16.7527 7.29915 16.7996 7.17873 16.8086 7.05264C16.8175 6.92655 16.788 6.80072 16.7239 6.69175L16.72 6.68511L16.2218 5.81307L16.2211 5.81187C16.159 5.70517 16.0667 5.61923 15.9558 5.5649C15.8458 5.51099 15.7224 5.49062 15.601 5.50627L14.132 5.73036C13.9919 5.75172 13.8488 5.72488 13.726 5.65424L11.901 4.60424C11.7772 4.533 11.6815 4.42148 11.6299 4.28827L11.0924 2.90077C11.0471 2.78331 10.967 2.68151 10.8633 2.61013C10.7598 2.5389 10.6373 2.50053 10.5116 2.5Z',
);
static final Path _path3 = _pathFromString( static final Path _path3 = _pathFromString(
'M10.0002 6.875C9.1714 6.875 8.37655 7.20424 7.7905 7.79029C7.20445 8.37635 6.87521 9.1712 6.87521 10C6.87521 10.6181 7.05848 11.2223 7.40186 11.7362C7.74524 12.2501 8.2333 12.6506 8.80432 12.8871C9.37534 13.1237 10.0037 13.1855 10.6099 13.065C11.2161 12.9444 11.7729 12.6467 12.2099 12.2097C12.647 11.7727 12.9446 11.2159 13.0652 10.6097C13.1857 10.0035 13.1239 9.37514 12.8873 8.80412C12.6508 8.2331 12.2503 7.74504 11.7364 7.40166C11.2225 7.05828 10.6183 6.875 10.0002 6.875ZM10.0002 8.125C9.50292 8.125 9.02601 8.32255 8.67438 8.67418C8.32275 9.02581 8.12521 9.50272 8.12521 10C8.12521 10.3708 8.23517 10.7334 8.4412 11.0417C8.64723 11.35 8.94006 11.5904 9.28267 11.7323C9.62529 11.8742 10.0023 11.9113 10.366 11.839C10.7297 11.7666 11.0638 11.5881 11.326 11.3258C11.5883 11.0636 11.7668 10.7295 11.8392 10.3658C11.9115 10.0021 11.8744 9.62508 11.7325 9.28247C11.5906 8.93986 11.3502 8.64703 11.0419 8.441C10.7336 8.23497 10.371 8.125 10.0002 8.125Z'); 'M10.0002 6.875C9.1714 6.875 8.37655 7.20424 7.7905 7.79029C7.20445 8.37635 6.87521 9.1712 6.87521 10C6.87521 10.6181 7.05848 11.2223 7.40186 11.7362C7.74524 12.2501 8.2333 12.6506 8.80432 12.8871C9.37534 13.1237 10.0037 13.1855 10.6099 13.065C11.2161 12.9444 11.7729 12.6467 12.2099 12.2097C12.647 11.7727 12.9446 11.2159 13.0652 10.6097C13.1857 10.0035 13.1239 9.37514 12.8873 8.80412C12.6508 8.2331 12.2503 7.74504 11.7364 7.40166C11.2225 7.05828 10.6183 6.875 10.0002 6.875ZM10.0002 8.125C9.50292 8.125 9.02601 8.32255 8.67438 8.67418C8.32275 9.02581 8.12521 9.50272 8.12521 10C8.12521 10.3708 8.23517 10.7334 8.4412 11.0417C8.64723 11.35 8.94006 11.5904 9.28267 11.7323C9.62529 11.8742 10.0023 11.9113 10.366 11.839C10.7297 11.7666 11.0638 11.5881 11.326 11.3258C11.5883 11.0636 11.7668 10.7295 11.8392 10.3658C11.9115 10.0021 11.8744 9.62508 11.7325 9.28247C11.5906 8.93986 11.3502 8.64703 11.0419 8.441C10.7336 8.23497 10.371 8.125 10.0002 8.125Z',
);
@override @override
bool shouldRepaint(covariant CustomPainter oldDelegate) { bool shouldRepaint(covariant CustomPainter oldDelegate) {
@ -236,8 +215,7 @@ class _SettingsIconPainter extends CustomPainter {
class _CameraIconPainter extends CustomPainter { class _CameraIconPainter extends CustomPainter {
@override @override
void paint(Canvas canvas, Size size) { void paint(Canvas canvas, Size size) {
final Matrix4 scale = final Matrix4 scale = Matrix4.diagonal3Values(size.width / 20, size.height / 20, 1.0);
Matrix4.diagonal3Values(size.width / 20, size.height / 20, 1.0);
Path path; Path path;
path = _path1.transform(scale.storage)..fillType = PathFillType.evenOdd; path = _path1.transform(scale.storage)..fillType = PathFillType.evenOdd;
@ -248,9 +226,11 @@ class _CameraIconPainter extends CustomPainter {
} }
static final Path _path1 = _pathFromString( static final Path _path1 = _pathFromString(
'M3.26366 17H16.7363C17.4857 17 18.0503 16.8123 18.4302 16.4369C18.8101 16.0615 19 15.5035 19 14.7631V7.01229C19 6.27188 18.8101 5.71397 18.4302 5.33855C18.0503 4.96313 17.4857 4.77542 16.7363 4.77542H14.6132C14.4154 4.77542 14.2567 4.76238 14.137 4.73631C14.0173 4.70503 13.9107 4.65549 13.817 4.58771C13.7233 4.51471 13.6219 4.41825 13.5126 4.29832L12.9115 3.61788C12.7242 3.41453 12.5212 3.26071 12.3027 3.15642C12.0893 3.05214 11.7953 3 11.4206 3H8.50911C8.13443 3 7.83781 3.05214 7.61925 3.15642C7.4059 3.26071 7.20555 3.41453 7.01821 3.61788L6.41717 4.29832C6.24545 4.48082 6.09193 4.60596 5.95663 4.67374C5.82134 4.74153 5.61058 4.77542 5.32437 4.77542H3.26366C2.50911 4.77542 1.94189 4.96313 1.56201 5.33855C1.18734 5.71397 1 6.27188 1 7.01229V14.7631C1 15.5035 1.18734 16.0615 1.56201 16.4369C1.94189 16.8123 2.50911 17 3.26366 17ZM3.27927 15.9207C2.89419 15.9207 2.59757 15.819 2.38942 15.6156C2.18647 15.4123 2.085 15.1099 2.085 14.7084V7.07486C2.085 6.67337 2.18647 6.37095 2.38942 6.1676C2.59757 5.95903 2.89419 5.85475 3.27927 5.85475H5.57415C5.9072 5.85475 6.1752 5.81825 6.37814 5.74525C6.58109 5.67225 6.77624 5.53147 6.96357 5.32291L7.55681 4.6581C7.76496 4.42346 7.9497 4.26965 8.11101 4.19665C8.27233 4.12365 8.50911 4.08715 8.82134 4.08715H11.1084C11.4258 4.08715 11.6626 4.12365 11.8187 4.19665C11.9801 4.26965 12.1648 4.42346 12.3729 4.6581L12.9662 5.32291C13.1535 5.53147 13.3487 5.67225 13.5516 5.74525C13.7546 5.81825 14.0225 5.85475 14.3556 5.85475H16.7207C17.1058 5.85475 17.4024 5.95903 17.6106 6.1676C17.8187 6.37095 17.9228 6.67337 17.9228 7.07486V14.7084C17.9228 15.1099 17.8187 15.4123 17.6106 15.6156C17.4024 15.819 17.1058 15.9207 16.7207 15.9207H3.27927ZM10 14.8101C10.7493 14.8101 11.4284 14.6302 12.0373 14.2704C12.6461 13.9054 13.1301 13.4179 13.4892 12.8078C13.8534 12.1926 14.0356 11.5095 14.0356 10.7587C14.0356 10.0078 13.8534 9.32477 13.4892 8.7095C13.1301 8.09423 12.6461 7.6067 12.0373 7.24693C11.4284 6.88194 10.7493 6.69944 10 6.69944C9.25585 6.69944 8.57676 6.88194 7.96271 7.24693C7.35386 7.6067 6.8673 8.09423 6.50304 8.7095C6.14397 9.32477 5.96444 10.0078 5.96444 10.7587C5.96444 11.5095 6.14397 12.1926 6.50304 12.8078C6.8673 13.4179 7.35386 13.9054 7.96271 14.2704C8.57676 14.6302 9.25585 14.8101 10 14.8101ZM10 13.7855C9.4484 13.7855 8.94363 13.6499 8.48569 13.3788C8.03296 13.1076 7.66869 12.7426 7.39289 12.2838C7.12229 11.825 6.98699 11.3166 6.98699 10.7587C6.98699 10.1955 7.12229 9.68454 7.39289 9.2257C7.66349 8.76685 8.02775 8.40447 8.48569 8.13855C8.94363 7.86741 9.4484 7.73184 10 7.73184C10.5568 7.73184 11.0616 7.86741 11.5143 8.13855C11.9722 8.40447 12.3365 8.76685 12.6071 9.2257C12.8829 9.68454 13.0208 10.1955 13.0208 10.7587C13.0208 11.3166 12.8829 11.825 12.6071 12.2838C12.3365 12.7426 11.9722 13.1076 11.5143 13.3788C11.0616 13.6499 10.5568 13.7855 10 13.7855ZM14.3556 8.04469C14.3556 8.30019 14.4467 8.51657 14.6288 8.69385C14.8109 8.86592 15.0269 8.95196 15.2767 8.95196C15.516 8.94674 15.7242 8.8581 15.9011 8.68603C16.0833 8.50875 16.1743 8.29497 16.1743 8.04469C16.1743 7.79963 16.0833 7.58845 15.9011 7.41117C15.7242 7.22868 15.516 7.13743 15.2767 7.13743C15.0269 7.13743 14.8109 7.22868 14.6288 7.41117C14.4467 7.58845 14.3556 7.79963 14.3556 8.04469Z'); 'M3.26366 17H16.7363C17.4857 17 18.0503 16.8123 18.4302 16.4369C18.8101 16.0615 19 15.5035 19 14.7631V7.01229C19 6.27188 18.8101 5.71397 18.4302 5.33855C18.0503 4.96313 17.4857 4.77542 16.7363 4.77542H14.6132C14.4154 4.77542 14.2567 4.76238 14.137 4.73631C14.0173 4.70503 13.9107 4.65549 13.817 4.58771C13.7233 4.51471 13.6219 4.41825 13.5126 4.29832L12.9115 3.61788C12.7242 3.41453 12.5212 3.26071 12.3027 3.15642C12.0893 3.05214 11.7953 3 11.4206 3H8.50911C8.13443 3 7.83781 3.05214 7.61925 3.15642C7.4059 3.26071 7.20555 3.41453 7.01821 3.61788L6.41717 4.29832C6.24545 4.48082 6.09193 4.60596 5.95663 4.67374C5.82134 4.74153 5.61058 4.77542 5.32437 4.77542H3.26366C2.50911 4.77542 1.94189 4.96313 1.56201 5.33855C1.18734 5.71397 1 6.27188 1 7.01229V14.7631C1 15.5035 1.18734 16.0615 1.56201 16.4369C1.94189 16.8123 2.50911 17 3.26366 17ZM3.27927 15.9207C2.89419 15.9207 2.59757 15.819 2.38942 15.6156C2.18647 15.4123 2.085 15.1099 2.085 14.7084V7.07486C2.085 6.67337 2.18647 6.37095 2.38942 6.1676C2.59757 5.95903 2.89419 5.85475 3.27927 5.85475H5.57415C5.9072 5.85475 6.1752 5.81825 6.37814 5.74525C6.58109 5.67225 6.77624 5.53147 6.96357 5.32291L7.55681 4.6581C7.76496 4.42346 7.9497 4.26965 8.11101 4.19665C8.27233 4.12365 8.50911 4.08715 8.82134 4.08715H11.1084C11.4258 4.08715 11.6626 4.12365 11.8187 4.19665C11.9801 4.26965 12.1648 4.42346 12.3729 4.6581L12.9662 5.32291C13.1535 5.53147 13.3487 5.67225 13.5516 5.74525C13.7546 5.81825 14.0225 5.85475 14.3556 5.85475H16.7207C17.1058 5.85475 17.4024 5.95903 17.6106 6.1676C17.8187 6.37095 17.9228 6.67337 17.9228 7.07486V14.7084C17.9228 15.1099 17.8187 15.4123 17.6106 15.6156C17.4024 15.819 17.1058 15.9207 16.7207 15.9207H3.27927ZM10 14.8101C10.7493 14.8101 11.4284 14.6302 12.0373 14.2704C12.6461 13.9054 13.1301 13.4179 13.4892 12.8078C13.8534 12.1926 14.0356 11.5095 14.0356 10.7587C14.0356 10.0078 13.8534 9.32477 13.4892 8.7095C13.1301 8.09423 12.6461 7.6067 12.0373 7.24693C11.4284 6.88194 10.7493 6.69944 10 6.69944C9.25585 6.69944 8.57676 6.88194 7.96271 7.24693C7.35386 7.6067 6.8673 8.09423 6.50304 8.7095C6.14397 9.32477 5.96444 10.0078 5.96444 10.7587C5.96444 11.5095 6.14397 12.1926 6.50304 12.8078C6.8673 13.4179 7.35386 13.9054 7.96271 14.2704C8.57676 14.6302 9.25585 14.8101 10 14.8101ZM10 13.7855C9.4484 13.7855 8.94363 13.6499 8.48569 13.3788C8.03296 13.1076 7.66869 12.7426 7.39289 12.2838C7.12229 11.825 6.98699 11.3166 6.98699 10.7587C6.98699 10.1955 7.12229 9.68454 7.39289 9.2257C7.66349 8.76685 8.02775 8.40447 8.48569 8.13855C8.94363 7.86741 9.4484 7.73184 10 7.73184C10.5568 7.73184 11.0616 7.86741 11.5143 8.13855C11.9722 8.40447 12.3365 8.76685 12.6071 9.2257C12.8829 9.68454 13.0208 10.1955 13.0208 10.7587C13.0208 11.3166 12.8829 11.825 12.6071 12.2838C12.3365 12.7426 11.9722 13.1076 11.5143 13.3788C11.0616 13.6499 10.5568 13.7855 10 13.7855ZM14.3556 8.04469C14.3556 8.30019 14.4467 8.51657 14.6288 8.69385C14.8109 8.86592 15.0269 8.95196 15.2767 8.95196C15.516 8.94674 15.7242 8.8581 15.9011 8.68603C16.0833 8.50875 16.1743 8.29497 16.1743 8.04469C16.1743 7.79963 16.0833 7.58845 15.9011 7.41117C15.7242 7.22868 15.516 7.13743 15.2767 7.13743C15.0269 7.13743 14.8109 7.22868 14.6288 7.41117C14.4467 7.58845 14.3556 7.79963 14.3556 8.04469Z',
);
static final Path _path2 = _pathFromString( static final Path _path2 = _pathFromString(
'M2.30754 15.6907C2.51782 15.8969 2.81748 16 3.20651 16H16.7856C17.1746 16 17.4743 15.8969 17.6846 15.6907C17.8949 15.4845 18 15.1778 18 14.7707V7.02974C18 6.6226 17.8949 6.31593 17.6846 6.10972C17.4743 5.89822 17.1746 5.79247 16.7856 5.79247H14.3963C14.0598 5.79247 13.7891 5.75545 13.584 5.68143C13.379 5.6074 13.1819 5.46464 12.9926 5.25314L12.3933 4.57898C12.183 4.34104 11.9964 4.18506 11.8334 4.11104C11.6757 4.03701 11.4365 4 11.1158 4H8.80532C8.4899 4 8.2507 4.03701 8.08773 4.11104C7.92476 4.18506 7.73813 4.34104 7.52785 4.57898L6.92854 5.25314C6.73928 5.46464 6.54214 5.6074 6.33711 5.68143C6.13208 5.75545 5.86134 5.79247 5.52489 5.79247H3.20651C2.81748 5.79247 2.51782 5.89822 2.30754 6.10972C2.10251 6.31593 2 6.6226 2 7.02974V14.7707C2 15.1778 2.10251 15.4845 2.30754 15.6907ZM9.99547 14C9.99547 14 8.76994 13.8432 8.23868 13.5297C7.71345 13.2162 7.29086 12.7941 6.97089 12.2636C6.65696 11.733 6.5 11.1451 6.5 10.5C6.5 9.84884 6.65696 9.25797 6.97089 8.72739C7.28482 8.19681 7.70742 7.77778 8.23868 7.47028C8.76994 7.15676 9.35554 7 9.99547 7C10.6414 7 11.7523 7.47028 11.7523 7.47028C11.7523 7.47028 12.7061 8.19681 13.0201 8.72739C13.34 9.25797 13.5 9.84884 13.5 10.5C13.5 11.1451 13.34 11.733 13.0201 12.2636C12.7061 12.7941 12.2835 13.2162 11.7523 13.5297C11.227 13.8432 9.99547 14 9.99547 14Z'); 'M2.30754 15.6907C2.51782 15.8969 2.81748 16 3.20651 16H16.7856C17.1746 16 17.4743 15.8969 17.6846 15.6907C17.8949 15.4845 18 15.1778 18 14.7707V7.02974C18 6.6226 17.8949 6.31593 17.6846 6.10972C17.4743 5.89822 17.1746 5.79247 16.7856 5.79247H14.3963C14.0598 5.79247 13.7891 5.75545 13.584 5.68143C13.379 5.6074 13.1819 5.46464 12.9926 5.25314L12.3933 4.57898C12.183 4.34104 11.9964 4.18506 11.8334 4.11104C11.6757 4.03701 11.4365 4 11.1158 4H8.80532C8.4899 4 8.2507 4.03701 8.08773 4.11104C7.92476 4.18506 7.73813 4.34104 7.52785 4.57898L6.92854 5.25314C6.73928 5.46464 6.54214 5.6074 6.33711 5.68143C6.13208 5.75545 5.86134 5.79247 5.52489 5.79247H3.20651C2.81748 5.79247 2.51782 5.89822 2.30754 6.10972C2.10251 6.31593 2 6.6226 2 7.02974V14.7707C2 15.1778 2.10251 15.4845 2.30754 15.6907ZM9.99547 14C9.99547 14 8.76994 13.8432 8.23868 13.5297C7.71345 13.2162 7.29086 12.7941 6.97089 12.2636C6.65696 11.733 6.5 11.1451 6.5 10.5C6.5 9.84884 6.65696 9.25797 6.97089 8.72739C7.28482 8.19681 7.70742 7.77778 8.23868 7.47028C8.76994 7.15676 9.35554 7 9.99547 7C10.6414 7 11.7523 7.47028 11.7523 7.47028C11.7523 7.47028 12.7061 8.19681 13.0201 8.72739C13.34 9.25797 13.5 9.84884 13.5 10.5C13.5 11.1451 13.34 11.733 13.0201 12.2636C12.7061 12.7941 12.2835 13.2162 11.7523 13.5297C11.227 13.8432 9.99547 14 9.99547 14Z',
);
@override @override
bool shouldRepaint(covariant CustomPainter oldDelegate) { bool shouldRepaint(covariant CustomPainter oldDelegate) {
@ -261,8 +241,7 @@ class _CameraIconPainter extends CustomPainter {
class _CalendarIconPainter extends CustomPainter { class _CalendarIconPainter extends CustomPainter {
@override @override
void paint(Canvas canvas, Size size) { void paint(Canvas canvas, Size size) {
final Matrix4 scale = final Matrix4 scale = Matrix4.diagonal3Values(size.width / 20, size.height / 20, 1.0);
Matrix4.diagonal3Values(size.width / 20, size.height / 20, 1.0);
Path path; Path path;
path = _path1.transform(scale.storage)..fillType = PathFillType.evenOdd; path = _path1.transform(scale.storage)..fillType = PathFillType.evenOdd;
@ -273,9 +252,11 @@ class _CalendarIconPainter extends CustomPainter {
} }
static final Path _path1 = _pathFromString( static final Path _path1 = _pathFromString(
'M16.7812 6.85938H3.28125V4.5L5 3H15L16.7812 4.5V6.85938Z'); 'M16.7812 6.85938H3.28125V4.5L5 3H15L16.7812 4.5V6.85938Z',
);
static final Path _path2 = _pathFromString( static final Path _path2 = _pathFromString(
'M6.5606 11.2462C7.07732 11.2462 7.4962 10.8273 7.4962 10.3106C7.4962 9.79388 7.07732 9.375 6.5606 9.375C6.04388 9.375 5.625 9.79388 5.625 10.3106C5.625 10.8273 6.04388 11.2462 6.5606 11.2462ZM7.4962 13.4356C7.4962 13.9523 7.07732 14.3712 6.5606 14.3712C6.04388 14.3712 5.625 13.9523 5.625 13.4356C5.625 12.9189 6.04388 12.5 6.5606 12.5C7.07732 12.5 7.4962 12.9189 7.4962 13.4356ZM10.0005 11.2462C10.5173 11.2462 10.9361 10.8273 10.9361 10.3106C10.9361 9.79388 10.5173 9.375 10.0005 9.375C9.48382 9.375 9.06494 9.79388 9.06494 10.3106C9.06494 10.8273 9.48382 11.2462 10.0005 11.2462ZM10.9361 13.4356C10.9361 13.9523 10.5173 14.3712 10.0005 14.3712C9.48382 14.3712 9.06494 13.9523 9.06494 13.4356C9.06494 12.9189 9.48382 12.5 10.0005 12.5C10.5173 12.5 10.9361 12.9189 10.9361 13.4356ZM13.4356 11.2462C13.9523 11.2462 14.3712 10.8273 14.3712 10.3106C14.3712 9.79388 13.9523 9.375 13.4356 9.375C12.9189 9.375 12.5 9.79388 12.5 10.3106C12.5 10.8273 12.9189 11.2462 13.4356 11.2462ZM17.5 5.625C17.5 3.89911 16.1009 2.5 14.375 2.5H5.625C3.89911 2.5 2.5 3.89911 2.5 5.625V14.375C2.5 16.1009 3.89911 17.5 5.625 17.5H14.375C16.1009 17.5 17.5 16.1009 17.5 14.375V5.625ZM3.75 7.5H16.25V14.375C16.25 15.4105 15.4105 16.25 14.375 16.25H5.625C4.58947 16.25 3.75 15.4105 3.75 14.375V7.5ZM5.625 3.75H14.375C15.4105 3.75 16.25 4.58947 16.25 5.625V6.25H3.75V5.625C3.75 4.58947 4.58947 3.75 5.625 3.75Z'); 'M6.5606 11.2462C7.07732 11.2462 7.4962 10.8273 7.4962 10.3106C7.4962 9.79388 7.07732 9.375 6.5606 9.375C6.04388 9.375 5.625 9.79388 5.625 10.3106C5.625 10.8273 6.04388 11.2462 6.5606 11.2462ZM7.4962 13.4356C7.4962 13.9523 7.07732 14.3712 6.5606 14.3712C6.04388 14.3712 5.625 13.9523 5.625 13.4356C5.625 12.9189 6.04388 12.5 6.5606 12.5C7.07732 12.5 7.4962 12.9189 7.4962 13.4356ZM10.0005 11.2462C10.5173 11.2462 10.9361 10.8273 10.9361 10.3106C10.9361 9.79388 10.5173 9.375 10.0005 9.375C9.48382 9.375 9.06494 9.79388 9.06494 10.3106C9.06494 10.8273 9.48382 11.2462 10.0005 11.2462ZM10.9361 13.4356C10.9361 13.9523 10.5173 14.3712 10.0005 14.3712C9.48382 14.3712 9.06494 13.9523 9.06494 13.4356C9.06494 12.9189 9.48382 12.5 10.0005 12.5C10.5173 12.5 10.9361 12.9189 10.9361 13.4356ZM13.4356 11.2462C13.9523 11.2462 14.3712 10.8273 14.3712 10.3106C14.3712 9.79388 13.9523 9.375 13.4356 9.375C12.9189 9.375 12.5 9.79388 12.5 10.3106C12.5 10.8273 12.9189 11.2462 13.4356 11.2462ZM17.5 5.625C17.5 3.89911 16.1009 2.5 14.375 2.5H5.625C3.89911 2.5 2.5 3.89911 2.5 5.625V14.375C2.5 16.1009 3.89911 17.5 5.625 17.5H14.375C16.1009 17.5 17.5 16.1009 17.5 14.375V5.625ZM3.75 7.5H16.25V14.375C16.25 15.4105 15.4105 16.25 14.375 16.25H5.625C4.58947 16.25 3.75 15.4105 3.75 14.375V7.5ZM5.625 3.75H14.375C15.4105 3.75 16.25 4.58947 16.25 5.625V6.25H3.75V5.625C3.75 4.58947 4.58947 3.75 5.625 3.75Z',
);
@override @override
bool shouldRepaint(covariant CustomPainter oldDelegate) { bool shouldRepaint(covariant CustomPainter oldDelegate) {
@ -286,8 +267,7 @@ class _CalendarIconPainter extends CustomPainter {
class _ConversationIconPainter extends CustomPainter { class _ConversationIconPainter extends CustomPainter {
@override @override
void paint(Canvas canvas, Size size) { void paint(Canvas canvas, Size size) {
final Matrix4 scale = final Matrix4 scale = Matrix4.diagonal3Values(size.width / 20, size.height / 20, 1.0);
Matrix4.diagonal3Values(size.width / 20, size.height / 20, 1.0);
Path path; Path path;
path = _path1.transform(scale.storage)..fillType = PathFillType.evenOdd; path = _path1.transform(scale.storage)..fillType = PathFillType.evenOdd;
@ -298,9 +278,11 @@ class _ConversationIconPainter extends CustomPainter {
} }
static final Path _path1 = _pathFromString( static final Path _path1 = _pathFromString(
'M14.4141 8.33333C14.4141 11.555 11.8024 14.1667 8.58073 14.1667C7.64487 14.1667 6.76047 13.9463 5.97663 13.5546L2.65625 14.4661L3.70864 11.5424C3.10106 10.6218 2.7474 9.51887 2.7474 8.33333C2.7474 5.11167 5.35907 2.5 8.58073 2.5C11.8024 2.5 14.4141 5.11167 14.4141 8.33333Z'); 'M14.4141 8.33333C14.4141 11.555 11.8024 14.1667 8.58073 14.1667C7.64487 14.1667 6.76047 13.9463 5.97663 13.5546L2.65625 14.4661L3.70864 11.5424C3.10106 10.6218 2.7474 9.51887 2.7474 8.33333C2.7474 5.11167 5.35907 2.5 8.58073 2.5C11.8024 2.5 14.4141 5.11167 14.4141 8.33333Z',
);
static final Path _path2 = _pathFromString( static final Path _path2 = _pathFromString(
'M8.5382 1.81665C4.84709 1.81665 1.85486 4.80888 1.85486 8.49998C1.85486 9.65241 2.1471 10.7384 2.66182 11.686L1.89645 13.6887C1.5494 14.5968 2.38481 15.5128 3.32097 15.2506L5.74289 14.5723C6.59409 14.9647 7.54146 15.1833 8.5382 15.1833C12.2293 15.1833 15.2215 12.1911 15.2215 8.49998C15.2215 4.80888 12.2293 1.81665 8.5382 1.81665ZM3.22153 8.49998C3.22153 5.56367 5.60188 3.18332 8.5382 3.18332C11.4745 3.18332 13.8549 5.56367 13.8549 8.49998C13.8549 11.4363 11.4745 13.8167 8.5382 13.8167C7.66578 13.8167 6.84431 13.607 6.11952 13.2361L5.88143 13.1142L3.30309 13.8364L4.17436 11.5565L3.99903 11.2698C3.5059 10.4636 3.22153 9.51607 3.22153 8.49998ZM16.5636 7.07206L16.1464 6.61586L16.2475 7.22577C16.317 7.64558 16.3533 8.07677 16.3533 8.51656C16.3533 8.69251 16.3475 8.86707 16.3361 9.04007L16.3328 9.08869L16.3542 9.13249C16.6951 9.83163 16.8175 10.5975 16.8175 11.5C16.8175 12.5161 16.5332 13.4636 16.04 14.2698L15.8647 14.5565L16.736 16.8363L14.1576 16.1142L13.9195 16.2361C13.1948 16.607 12.3733 16.8166 11.5009 16.8166C10.5879 16.8166 9.87033 16.6947 9.19041 16.3496L9.14498 16.3266L9.09417 16.3303C8.90419 16.3441 8.71231 16.3511 8.51875 16.3511C8.10958 16.3511 7.70785 16.3197 7.31582 16.2593L6.72389 16.1681L7.16334 16.575C8.31731 17.6436 9.75888 18.1833 11.5009 18.1833C12.4976 18.1833 13.445 17.9647 14.2962 17.5723L16.7181 18.2506C17.6543 18.5128 18.4897 17.5968 18.1426 16.6887L17.3772 14.6859C17.892 13.7384 18.1842 12.6524 18.1842 11.5C18.1842 9.75761 17.6387 8.24759 16.5636 7.07206Z'); 'M8.5382 1.81665C4.84709 1.81665 1.85486 4.80888 1.85486 8.49998C1.85486 9.65241 2.1471 10.7384 2.66182 11.686L1.89645 13.6887C1.5494 14.5968 2.38481 15.5128 3.32097 15.2506L5.74289 14.5723C6.59409 14.9647 7.54146 15.1833 8.5382 15.1833C12.2293 15.1833 15.2215 12.1911 15.2215 8.49998C15.2215 4.80888 12.2293 1.81665 8.5382 1.81665ZM3.22153 8.49998C3.22153 5.56367 5.60188 3.18332 8.5382 3.18332C11.4745 3.18332 13.8549 5.56367 13.8549 8.49998C13.8549 11.4363 11.4745 13.8167 8.5382 13.8167C7.66578 13.8167 6.84431 13.607 6.11952 13.2361L5.88143 13.1142L3.30309 13.8364L4.17436 11.5565L3.99903 11.2698C3.5059 10.4636 3.22153 9.51607 3.22153 8.49998ZM16.5636 7.07206L16.1464 6.61586L16.2475 7.22577C16.317 7.64558 16.3533 8.07677 16.3533 8.51656C16.3533 8.69251 16.3475 8.86707 16.3361 9.04007L16.3328 9.08869L16.3542 9.13249C16.6951 9.83163 16.8175 10.5975 16.8175 11.5C16.8175 12.5161 16.5332 13.4636 16.04 14.2698L15.8647 14.5565L16.736 16.8363L14.1576 16.1142L13.9195 16.2361C13.1948 16.607 12.3733 16.8166 11.5009 16.8166C10.5879 16.8166 9.87033 16.6947 9.19041 16.3496L9.14498 16.3266L9.09417 16.3303C8.90419 16.3441 8.71231 16.3511 8.51875 16.3511C8.10958 16.3511 7.70785 16.3197 7.31582 16.2593L6.72389 16.1681L7.16334 16.575C8.31731 17.6436 9.75888 18.1833 11.5009 18.1833C12.4976 18.1833 13.445 17.9647 14.2962 17.5723L16.7181 18.2506C17.6543 18.5128 18.4897 17.5968 18.1426 16.6887L17.3772 14.6859C17.892 13.7384 18.1842 12.6524 18.1842 11.5C18.1842 9.75761 17.6387 8.24759 16.5636 7.07206Z',
);
@override @override
bool shouldRepaint(covariant CustomPainter oldDelegate) { bool shouldRepaint(covariant CustomPainter oldDelegate) {
@ -312,24 +294,23 @@ class _GeometryIconPainter extends CustomPainter {
@override @override
void paint(Canvas canvas, Size canvasSize) { void paint(Canvas canvas, Size canvasSize) {
const Size size = Size(20, 20); const Size size = Size(20, 20);
canvas.scale( canvas.scale(canvasSize.width / size.width, canvasSize.height / size.height);
canvasSize.width / size.width, canvasSize.height / size.height);
final Paint paint = Paint()..color = const Color(0xFFF84F39); final Paint paint = Paint()..color = const Color(0xFFF84F39);
final Rect frame = Offset.zero & size; final Rect frame = Offset.zero & size;
canvas.drawDRRect( canvas.drawDRRect(
RRect.fromRectAndRadius(frame, const Radius.elliptical(5, 4)), RRect.fromRectAndRadius(frame, const Radius.elliptical(5, 4)),
RRect.fromRectAndRadius( RRect.fromRectAndRadius(frame.deflate(1), const Radius.elliptical(4, 3)),
frame.deflate(1), const Radius.elliptical(4, 3)), paint,
paint); );
canvas.drawRRect( canvas.drawRRect(
RRect.fromRectAndRadius( RRect.fromRectAndRadius(const Rect.fromLTWH(3, 3, 6, 6), const Radius.elliptical(2, 1)),
const Rect.fromLTWH(3, 3, 6, 6), const Radius.elliptical(2, 1)), paint,
paint); );
canvas.drawRRect( canvas.drawRRect(
RRect.fromRectAndRadius( RRect.fromRectAndRadius(const Rect.fromLTWH(11, 11, 6, 6), const Radius.elliptical(2, 1)),
const Rect.fromLTWH(11, 11, 6, 6), const Radius.elliptical(2, 1)), paint,
paint); );
canvas.drawCircle(const Offset(14, 6), 3, paint); canvas.drawCircle(const Offset(14, 6), 3, paint);
canvas.drawCircle(const Offset(6, 14), 3, paint); canvas.drawCircle(const Offset(6, 14), 3, paint);
} }

View File

@ -19,25 +19,24 @@ class PictureCachePage extends StatelessWidget {
// pinned: true, // pinned: true,
// expandedHeight: 50.0, // expandedHeight: 50.0,
// forceElevated: innerBoxIsScrolled, // forceElevated: innerBoxIsScrolled,
bottom: TabBar( bottom: TabBar(tabs: kTabNames.map((String name) => Tab(text: name)).toList()),
tabs: kTabNames.map((String name) => Tab(text: name)).toList(),
),
), ),
body: TabBarView( body: TabBarView(
key: const Key('tabbar_view'), // this key is used by the driver test key: const Key('tabbar_view'), // this key is used by the driver test
children: kTabNames.map((String name) { children:
return SafeArea( kTabNames.map((String name) {
top: false, return SafeArea(
bottom: false, top: false,
child: Builder( bottom: false,
builder: (BuildContext context) { child: Builder(
return ListView.builder( builder: (BuildContext context) {
itemBuilder: (BuildContext context, int index) => ListItem(index: index), return ListView.builder(
); itemBuilder: (BuildContext context, int index) => ListItem(index: index),
}, );
), },
); ),
}).toList(), );
}).toList(),
), ),
), ),
); );
@ -56,35 +55,21 @@ class ListItem extends StatelessWidget {
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
final List<Widget> contents = <Widget>[ final List<Widget> contents = <Widget>[
const SizedBox( const SizedBox(height: 15),
height: 15,
),
_buildUserInfo(), _buildUserInfo(),
const SizedBox( const SizedBox(height: 10),
height: 10,
),
]; ];
if (index % 3 != 0) { if (index % 3 != 0) {
contents.add(_buildImageContent()); contents.add(_buildImageContent());
} else { } else {
contents.addAll(<Widget>[ contents.addAll(<Widget>[
Padding( Padding(padding: const EdgeInsets.only(left: 40, right: 15), child: _buildContentText()),
padding: const EdgeInsets.only(left: 40, right: 15), const SizedBox(height: 10),
child: _buildContentText(), Padding(padding: const EdgeInsets.only(left: 40, right: 15), child: _buildBottomRow()),
),
const SizedBox(
height: 10,
),
Padding(
padding: const EdgeInsets.only(left: 40, right: 15),
child: _buildBottomRow(),
),
]); ]);
} }
contents.addAll(<Widget>[ contents.addAll(<Widget>[
const SizedBox( const SizedBox(height: 13),
height: 13,
),
buildDivider(0.5, const EdgeInsets.only(left: 40, right: 15)), buildDivider(0.5, const EdgeInsets.only(left: 40, right: 15)),
]); ]);
return MaterialButton( return MaterialButton(
@ -112,21 +97,14 @@ class ListItem extends StatelessWidget {
Widget _buildImageContent() { Widget _buildImageContent() {
return Row( return Row(
children: <Widget>[ children: <Widget>[
const SizedBox( const SizedBox(width: 40),
width: 40,
),
Expanded( Expanded(
child: Column( child: Column(
mainAxisSize: MainAxisSize.min, mainAxisSize: MainAxisSize.min,
crossAxisAlignment: CrossAxisAlignment.start, crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[ children: <Widget>[
Padding( Padding(padding: const EdgeInsets.only(right: 30), child: _buildContentText()),
padding: const EdgeInsets.only(right: 30), const SizedBox(height: 10),
child: _buildContentText(),
),
const SizedBox(
height: 10,
),
_buildBottomRow(), _buildBottomRow(),
], ],
), ),
@ -138,9 +116,7 @@ class ListItem extends StatelessWidget {
width: 110, width: 110,
height: 70, height: 70,
), ),
const SizedBox( const SizedBox(width: 15),
width: 15,
),
], ],
); );
} }
@ -148,9 +124,7 @@ class ListItem extends StatelessWidget {
Widget _buildContentText() { Widget _buildContentText() {
return const Text( return const Text(
kMockChineseTitle, kMockChineseTitle,
style: TextStyle( style: TextStyle(fontSize: 16),
fontSize: 16,
),
maxLines: 2, maxLines: 2,
overflow: TextOverflow.ellipsis, overflow: TextOverflow.ellipsis,
); );
@ -160,9 +134,7 @@ class ListItem extends StatelessWidget {
return Row( return Row(
children: <Widget>[ children: <Widget>[
Container( Container(
padding: const EdgeInsets.symmetric( padding: const EdgeInsets.symmetric(horizontal: 7),
horizontal: 7,
),
height: 16, height: 16,
alignment: Alignment.center, alignment: Alignment.center,
decoration: BoxDecoration( decoration: BoxDecoration(
@ -171,48 +143,27 @@ class ListItem extends StatelessWidget {
), ),
child: Row( child: Row(
children: <Widget>[ children: <Widget>[
const SizedBox( const SizedBox(width: 3),
width: 3,
),
Text( Text(
'hot:${_convertCountToStr(kMockCount)}', 'hot:${_convertCountToStr(kMockCount)}',
style: const TextStyle( style: const TextStyle(color: Color(0xFFE5645F), fontSize: 11),
color: Color(0xFFE5645F),
fontSize: 11,
),
), ),
], ],
), ),
), ),
const SizedBox( const SizedBox(width: 9),
width: 9, const Text('ans:$kMockCount', style: TextStyle(color: Color(0xFF999999), fontSize: 11)),
), const SizedBox(width: 9),
const Text( const Text('like:$kMockCount', style: TextStyle(color: Color(0xFF999999), fontSize: 11)),
'ans:$kMockCount',
style: TextStyle(
color: Color(0xFF999999),
fontSize: 11,
),
),
const SizedBox(
width: 9,
),
const Text(
'like:$kMockCount',
style: TextStyle(
color: Color(0xFF999999),
fontSize: 11,
),
),
], ],
); );
} }
String _convertCountToStr(int count) { String _convertCountToStr(int count) {
return switch (count) { return switch (count) {
< 10000 => count.toString(), < 10000 => count.toString(),
< 100000 => '${(count / 10000).toStringAsPrecision(2)}w', < 100000 => '${(count / 10000).toStringAsPrecision(2)}w',
_ => '${(count / 10000).floor()}w', _ => '${(count / 10000).floor()}w',
}; };
} }
@ -221,42 +172,26 @@ class ListItem extends StatelessWidget {
onTap: () {}, onTap: () {},
child: Row( child: Row(
children: <Widget>[ children: <Widget>[
Container( Container(width: 40, alignment: Alignment.center, child: _buildRankText()),
width: 40, alignment: Alignment.center, child: _buildRankText()), const CircleAvatar(radius: 11.5),
const CircleAvatar( const SizedBox(width: 6),
radius: 11.5,
),
const SizedBox(
width: 6,
),
ConstrainedBox( ConstrainedBox(
constraints: const BoxConstraints(maxWidth: 250), constraints: const BoxConstraints(maxWidth: 250),
child: const Text( child: const Text(
kMockName, kMockName,
maxLines: 1, maxLines: 1,
overflow: TextOverflow.ellipsis, overflow: TextOverflow.ellipsis,
style: TextStyle( style: TextStyle(fontSize: 14, fontWeight: FontWeight.bold),
fontSize: 14,
fontWeight: FontWeight.bold,
),
), ),
), ),
const SizedBox( const SizedBox(width: 4),
width: 4, const SizedBox(width: 15),
),
const SizedBox(
width: 15,
),
], ],
), ),
); );
} }
Widget buildDivider(double height, EdgeInsets padding) { Widget buildDivider(double height, EdgeInsets padding) {
return Container( return Container(padding: padding, height: height, color: const Color(0xFFF5F5F5));
padding: padding,
height: height,
color: const Color(0xFFF5F5F5),
);
} }
} }

View File

@ -19,15 +19,14 @@ class PictureCacheComplexityScoringPage extends StatelessWidget {
// pinned: true, // pinned: true,
// expandedHeight: 50.0, // expandedHeight: 50.0,
// forceElevated: innerBoxIsScrolled, // forceElevated: innerBoxIsScrolled,
bottom: TabBar( bottom: TabBar(tabs: kTabNames.map((String name) => Tab(text: name)).toList()),
tabs: kTabNames.map((String name) => Tab(text: name)).toList(),
),
), ),
body: TabBarView( body: TabBarView(
key: const Key('tabbar_view_complexity'), // this key is used by the driver test key: const Key('tabbar_view_complexity'), // this key is used by the driver test
children: kTabNames.map((String name) { children:
return _buildComplexityScoringWidgets(name); kTabNames.map((String name) {
}).toList(), return _buildComplexityScoringWidgets(name);
}).toList(),
), ),
), ),
); );
@ -38,10 +37,12 @@ class PictureCacheComplexityScoringPage extends StatelessWidget {
// //
// Eventually we can extend this to add new test cases based on the tab name. // Eventually we can extend this to add new test cases based on the tab name.
Widget _buildComplexityScoringWidgets(String name) { Widget _buildComplexityScoringWidgets(String name) {
return Column(children: <Widget>[ return Column(
Slider(value: 50, label: 'Slider 1', onChanged: (double _) {}, max: 100, divisions: 10,), children: <Widget>[
Slider(value: 50, label: 'Slider 2', onChanged: (double _) {}, max: 100, divisions: 10,), Slider(value: 50, label: 'Slider 1', onChanged: (double _) {}, max: 100, divisions: 10),
Slider(value: 50, label: 'Slider 3', onChanged: (double _) {}, max: 100, divisions: 10,), Slider(value: 50, label: 'Slider 2', onChanged: (double _) {}, max: 100, divisions: 10),
]); Slider(value: 50, label: 'Slider 3', onChanged: (double _) {}, max: 100, divisions: 10),
],
);
} }
} }

View File

@ -13,7 +13,8 @@ class PostBackdropFilterPage extends StatefulWidget {
State<PostBackdropFilterPage> createState() => _PostBackdropFilterPageState(); State<PostBackdropFilterPage> createState() => _PostBackdropFilterPageState();
} }
class _PostBackdropFilterPageState extends State<PostBackdropFilterPage> with TickerProviderStateMixin { class _PostBackdropFilterPageState extends State<PostBackdropFilterPage>
with TickerProviderStateMixin {
bool _includeBackdropFilter = false; bool _includeBackdropFilter = false;
late AnimationController animation; late AnimationController animation;
@ -60,17 +61,20 @@ class _PostBackdropFilterPageState extends State<PostBackdropFilterPage> with Ti
children: <Widget>[ children: <Widget>[
Expanded( Expanded(
child: RepaintBoundary( child: RepaintBoundary(
child: Center( child: Center(
child: AnimatedBuilder( child: AnimatedBuilder(
animation: animation, animation: animation,
builder: (BuildContext c, Widget? w) { builder: (BuildContext c, Widget? w) {
final int val = (animation.value * 255).round(); final int val = (animation.value * 255).round();
return Container( return Container(
width: 50, width: 50,
height: 50, height: 50,
color: Color.fromARGB(255, val, val, val)); color: Color.fromARGB(255, val, val, val),
}), );
)), },
),
),
),
), ),
getConditionalBackdrop(), getConditionalBackdrop(),
RepaintBoundary( RepaintBoundary(
@ -83,12 +87,18 @@ class _PostBackdropFilterPageState extends State<PostBackdropFilterPage> with Ti
Checkbox( Checkbox(
key: const Key('bdf-checkbox'), // this key is used by the driver test key: const Key('bdf-checkbox'), // this key is used by the driver test
value: _includeBackdropFilter, value: _includeBackdropFilter,
onChanged: (bool? v) => setState(() { _includeBackdropFilter = v ?? false; }), onChanged:
(bool? v) => setState(() {
_includeBackdropFilter = v ?? false;
}),
), ),
MaterialButton( MaterialButton(
key: const Key('bdf-animate'), // this key is used by the driver test key: const Key('bdf-animate'), // this key is used by the driver test
child: const Text('Animate'), child: const Text('Animate'),
onPressed: () => setState(() { animation.repeat(); }), onPressed:
() => setState(() {
animation.repeat();
}),
), ),
], ],
), ),

View File

@ -13,8 +13,7 @@ class RasterCacheUseMemory extends StatefulWidget {
State<RasterCacheUseMemory> createState() => _RasterCacheUseMemoryState(); State<RasterCacheUseMemory> createState() => _RasterCacheUseMemoryState();
} }
class _RasterCacheUseMemoryState extends State<RasterCacheUseMemory> class _RasterCacheUseMemoryState extends State<RasterCacheUseMemory> with TickerProviderStateMixin {
with TickerProviderStateMixin {
final ScrollController _controller = ScrollController(); final ScrollController _controller = ScrollController();
@override @override
@ -22,16 +21,13 @@ class _RasterCacheUseMemoryState extends State<RasterCacheUseMemory>
super.initState(); super.initState();
_controller.addListener(() { _controller.addListener(() {
if (_controller.offset < 5) { if (_controller.offset < 5) {
_controller.animateTo(20, _controller.animateTo(20, duration: const Duration(milliseconds: 1000), curve: Curves.ease);
duration: const Duration(milliseconds: 1000), curve: Curves.ease);
} else if (_controller.offset >= 19) { } else if (_controller.offset >= 19) {
_controller.animateTo(0, _controller.animateTo(0, duration: const Duration(milliseconds: 1000), curve: Curves.ease);
duration: const Duration(milliseconds: 1000), curve: Curves.ease);
} }
}); });
Timer(const Duration(milliseconds: 1000), () { Timer(const Duration(milliseconds: 1000), () {
_controller.animateTo(150, _controller.animateTo(150, duration: const Duration(milliseconds: 1000), curve: Curves.ease);
duration: const Duration(milliseconds: 1000), curve: Curves.ease);
}); });
} }
@ -44,17 +40,8 @@ class _RasterCacheUseMemoryState extends State<RasterCacheUseMemory>
children: <Widget>[ children: <Widget>[
RepaintBoundary( RepaintBoundary(
child: ImageFiltered( child: ImageFiltered(
imageFilter: ImageFilter.blur( imageFilter: ImageFilter.blur(sigmaX: 4, sigmaY: 4),
sigmaX: 4, child: RepaintBoundary(child: Container(width: 50, height: 50, color: Colors.red)),
sigmaY: 4,
),
child: RepaintBoundary(
child: Container(
width: 50,
height: 50,
color: Colors.red,
),
),
), ),
), ),
ShaderMask( ShaderMask(
@ -72,50 +59,32 @@ class _RasterCacheUseMemoryState extends State<RasterCacheUseMemory>
child: Column( child: Column(
children: <Widget>[ children: <Widget>[
ImageFiltered( ImageFiltered(
imageFilter: ImageFilter.blur( imageFilter: ImageFilter.blur(sigmaX: 4, sigmaY: 4),
sigmaX: 4,
sigmaY: 4,
),
child: Row( child: Row(
children: <Widget>[ children: <Widget>[
ImageFiltered( ImageFiltered(
imageFilter: ImageFilter.blur( imageFilter: ImageFilter.blur(sigmaX: 4, sigmaY: 4),
sigmaX: 4,
sigmaY: 4,
),
child: RepaintBoundary( child: RepaintBoundary(
child: Container( child: Container(
margin: const EdgeInsets.fromLTRB(10, 5, 10, 5), margin: const EdgeInsets.fromLTRB(10, 5, 10, 5),
decoration: BoxDecoration( decoration: BoxDecoration(
color: Colors.white70, color: Colors.white70,
boxShadow: const <BoxShadow>[ boxShadow: const <BoxShadow>[BoxShadow(blurRadius: 5.0)],
BoxShadow(
blurRadius: 5.0,
),
],
borderRadius: BorderRadius.circular(5.0), borderRadius: BorderRadius.circular(5.0),
), ),
child: const FlutterLogo( child: const FlutterLogo(size: 50),
size: 50,
),
), ),
), ),
) ),
], ],
), ),
) ),
], ],
), ),
), ),
), ),
const RepaintBoundary( const RepaintBoundary(child: FlutterLogo(size: 50)),
child: FlutterLogo( Container(height: 800),
size: 50,
),
),
Container(
height: 800,
),
], ],
), ),
); );

View File

@ -14,16 +14,14 @@ class RRectBlur extends StatefulWidget {
State<RRectBlur> createState() => _RRectBlurPageState(); State<RRectBlur> createState() => _RRectBlurPageState();
} }
class _RRectBlurPageState extends State<RRectBlur> class _RRectBlurPageState extends State<RRectBlur> with SingleTickerProviderStateMixin {
with SingleTickerProviderStateMixin {
late final AnimationController controller; late final AnimationController controller;
double tick = 0.0; double tick = 0.0;
@override @override
void initState() { void initState() {
super.initState(); super.initState();
controller = controller = AnimationController(vsync: this, duration: const Duration(hours: 1));
AnimationController(vsync: this, duration: const Duration(hours: 1));
controller.addListener(() { controller.addListener(() {
setState(() { setState(() {
tick += 1; tick += 1;
@ -75,22 +73,15 @@ class PointsPainter extends CustomPainter {
const double freq = 0.25; const double freq = 0.25;
const int circleCount = 40; const int circleCount = 40;
for (int i = 0; i < circleCount; ++i) { for (int i = 0; i < circleCount; ++i) {
final double radius = final double radius = 25 * cos(i + (1.0 * 2.0 * 3.1415 * tick) / 60.0) + 25;
25 * cos(i + (1.0 * 2.0 * 3.1415 * tick) / 60.0) + final Paint paint =
25; Paint()
final Paint paint = Paint() ..style = PaintingStyle.fill
..style = PaintingStyle.fill ..filterQuality = FilterQuality.low
..filterQuality = FilterQuality.low ..maskFilter = MaskFilter.blur(BlurStyle.normal, radius);
..maskFilter = MaskFilter.blur(BlurStyle.normal, radius); final double yval = halfHeight * sin(i + (freq * 2.0 * 3.1415 * tick) / 60.0) + halfHeight;
final double yval =
halfHeight * sin(i + (freq * 2.0 * 3.1415 * tick) / 60.0) +
halfHeight;
final double xval = (i.toDouble() / circleCount) * size.width; final double xval = (i.toDouble() / circleCount) * size.width;
canvas.drawCircle( canvas.drawCircle(Offset(xval, yval), 50, paint..color = kColors[i % kColors.length]);
Offset(xval, yval),
50,
paint..color = kColors[i % kColors.length],
);
} }
} }

View File

@ -12,8 +12,7 @@ class ShaderMaskCachePage extends StatefulWidget {
State<ShaderMaskCachePage> createState() => _ShaderMaskCachePageState(); State<ShaderMaskCachePage> createState() => _ShaderMaskCachePageState();
} }
class _ShaderMaskCachePageState extends State<ShaderMaskCachePage> class _ShaderMaskCachePageState extends State<ShaderMaskCachePage> with TickerProviderStateMixin {
with TickerProviderStateMixin {
final ScrollController _controller = ScrollController(); final ScrollController _controller = ScrollController();
@override @override
@ -21,7 +20,11 @@ class _ShaderMaskCachePageState extends State<ShaderMaskCachePage>
super.initState(); super.initState();
_controller.addListener(() { _controller.addListener(() {
if (_controller.offset < 10) { if (_controller.offset < 10) {
_controller.animateTo(100, duration: const Duration(milliseconds: 1000), curve: Curves.ease); _controller.animateTo(
100,
duration: const Duration(milliseconds: 1000),
curve: Curves.ease,
);
} else if (_controller.offset > 90) { } else if (_controller.offset > 90) {
_controller.animateTo(0, duration: const Duration(milliseconds: 1000), curve: Curves.ease); _controller.animateTo(0, duration: const Duration(milliseconds: 1000), curve: Curves.ease);
} }
@ -60,12 +63,9 @@ class _ShaderMaskCachePageState extends State<ShaderMaskCachePage>
}, },
child: Container( child: Container(
clipBehavior: Clip.antiAlias, clipBehavior: Clip.antiAlias,
decoration: const BoxDecoration(boxShadow: <BoxShadow>[ decoration: const BoxDecoration(
BoxShadow( boxShadow: <BoxShadow>[BoxShadow(color: Colors.white, blurRadius: 5.0)],
color: Colors.white, ),
blurRadius: 5.0,
),
]),
child: ListItem(index: index), child: ListItem(index: index),
), ),
); );

View File

@ -11,8 +11,7 @@ class SimpleScroll extends StatelessWidget {
Widget build(BuildContext context) { Widget build(BuildContext context) {
return ListView( return ListView(
children: <Widget>[ children: <Widget>[
for (int n = 0; n < 200; n += 1) for (int n = 0; n < 200; n += 1) SizedBox(height: 40.0, child: Text('$n')),
SizedBox(height: 40.0, child: Text('$n')),
], ],
); );
} }

View File

@ -14,7 +14,7 @@ class SlidersPage extends StatefulWidget {
} }
class _SlidersPageState extends State<SlidersPage> with TickerProviderStateMixin { class _SlidersPageState extends State<SlidersPage> with TickerProviderStateMixin {
late AnimationController _sliderController; late AnimationController _sliderController;
late Animation<double> _sliderAnimation; late Animation<double> _sliderAnimation;
double _sliderValue = 0.0; double _sliderValue = 0.0;
RangeValues _rangeSliderValues = const RangeValues(0.0, 1.0); RangeValues _rangeSliderValues = const RangeValues(0.0, 1.0);
@ -22,20 +22,17 @@ class _SlidersPageState extends State<SlidersPage> with TickerProviderStateMixin
@override @override
void initState() { void initState() {
super.initState(); super.initState();
_sliderController = AnimationController( _sliderController = AnimationController(duration: const Duration(seconds: 1), vsync: this)
duration: const Duration(seconds: 1), ..repeat();
vsync: this, _sliderAnimation = Tween<double>(begin: 0, end: 1).animate(_sliderController)..addListener(() {
)..repeat(); setState(() {
_sliderAnimation = Tween<double>(begin: 0, end: 1).animate(_sliderController) _sliderValue = _sliderAnimation.value;
..addListener(() { _rangeSliderValues = RangeValues(
setState(() { clampDouble(_sliderAnimation.value, 0, 0.45),
_sliderValue = _sliderAnimation.value; 1.0 - clampDouble(_sliderAnimation.value, 0, 0.45),
_rangeSliderValues = RangeValues( );
clampDouble(_sliderAnimation.value, 0, 0.45),
1.0 - clampDouble(_sliderAnimation.value, 0, 0.45),
);
});
}); });
});
} }
@override @override
@ -50,14 +47,8 @@ class _SlidersPageState extends State<SlidersPage> with TickerProviderStateMixin
child: Column( child: Column(
mainAxisAlignment: MainAxisAlignment.center, mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[ children: <Widget>[
Slider( Slider(value: _sliderValue, onChanged: (double value) {}),
value: _sliderValue, RangeSlider(values: _rangeSliderValues, onChanged: (RangeValues values) {}),
onChanged: (double value) { },
),
RangeSlider(
values: _rangeSliderValues,
onChanged: (RangeValues values) { },
),
], ],
), ),
); );

View File

@ -13,13 +13,7 @@ class TextPage extends StatelessWidget {
child: Column( child: Column(
mainAxisAlignment: MainAxisAlignment.center, mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[ children: <Widget>[
SizedBox( SizedBox(width: 200, height: 100, child: TextField(key: Key('basic-textfield'))),
width: 200,
height: 100,
child: TextField(
key: Key('basic-textfield'),
),
),
], ],
), ),
); );

View File

@ -30,17 +30,25 @@ class VeryLongPictureScrollingPerfState extends State<VeryLongPictureScrollingPe
Row( Row(
children: <Widget>[ children: <Widget>[
const Text('list:'), const Text('list:'),
Checkbox(value: useList, onChanged: (bool? value) => setState(() { Checkbox(
useList = value!; value: useList,
}),), onChanged:
(bool? value) => setState(() {
useList = value!;
}),
),
], ],
), ),
Row( Row(
children: <Widget>[ children: <Widget>[
const Text('consolidate:'), const Text('consolidate:'),
Checkbox(value: consolidate, onChanged: (bool? value) => setState(() { Checkbox(
consolidate = value!; value: consolidate,
}),), onChanged:
(bool? value) => setState(() {
consolidate = value!;
}),
),
], ],
), ),
], ],
@ -49,48 +57,44 @@ class VeryLongPictureScrollingPerfState extends State<VeryLongPictureScrollingPe
body: SizedBox( body: SizedBox(
width: MediaQuery.of(context).size.width, width: MediaQuery.of(context).size.width,
height: MediaQuery.of(context).size.height, height: MediaQuery.of(context).size.height,
child: useList child:
? ListView.builder( useList
key: const ValueKey<String>('vlp_list_view_scrollable'), ? ListView.builder(
scrollDirection: Axis.horizontal, key: const ValueKey<String>('vlp_list_view_scrollable'),
clipBehavior: Clip.none, scrollDirection: Axis.horizontal,
itemCount: (waveData.length / 200).ceil(), clipBehavior: Clip.none,
itemExtent: 100, itemCount: (waveData.length / 200).ceil(),
itemBuilder: (BuildContext context, int index) => CustomPaint( itemExtent: 100,
painter: PaintSomeTest( itemBuilder:
waveData: waveData, (BuildContext context, int index) => CustomPaint(
from: index * 200, painter: PaintSomeTest(
to: min((index + 1) * 200, waveData.length - 1), waveData: waveData,
) from: index * 200,
), to: min((index + 1) * 200, waveData.length - 1),
) ),
: SingleChildScrollView( ),
key: const ValueKey<String>('vlp_single_child_scrollable'), )
scrollDirection: Axis.horizontal, : SingleChildScrollView(
child: SizedBox( key: const ValueKey<String>('vlp_single_child_scrollable'),
width: MediaQuery.of(context).size.width * 20, scrollDirection: Axis.horizontal,
height: MediaQuery.of(context).size.height, child: SizedBox(
child: RepaintBoundary( width: MediaQuery.of(context).size.width * 20,
child: CustomPaint( height: MediaQuery.of(context).size.height,
isComplex: true, child: RepaintBoundary(
painter: PaintTest( child: CustomPaint(
consolidate: consolidate, isComplex: true,
waveData: waveData, painter: PaintTest(consolidate: consolidate, waveData: waveData),
),
),
),
), ),
),
),
),
),
), ),
); );
} }
} }
class PaintTest extends CustomPainter { class PaintTest extends CustomPainter {
const PaintTest({ const PaintTest({required this.consolidate, required this.waveData});
required this.consolidate,
required this.waveData,
});
final bool consolidate; final bool consolidate;
final Int16List waveData; final Int16List waveData;
@ -102,23 +106,26 @@ class PaintTest extends CustomPainter {
const double strokeSize = .5; const double strokeSize = .5;
const double zoomFactor = .5; const double zoomFactor = .5;
final Paint paintPos = Paint() final Paint paintPos =
..color = Colors.pink Paint()
..strokeWidth = strokeSize ..color = Colors.pink
..isAntiAlias = false ..strokeWidth = strokeSize
..style = PaintingStyle.stroke; ..isAntiAlias = false
..style = PaintingStyle.stroke;
final Paint paintNeg = Paint() final Paint paintNeg =
..color = Colors.pink Paint()
..strokeWidth = strokeSize ..color = Colors.pink
..isAntiAlias = false ..strokeWidth = strokeSize
..style = PaintingStyle.stroke; ..isAntiAlias = false
..style = PaintingStyle.stroke;
final Paint paintZero = Paint() final Paint paintZero =
..color = Colors.green Paint()
..strokeWidth = strokeSize ..color = Colors.green
..isAntiAlias = false ..strokeWidth = strokeSize
..style = PaintingStyle.stroke; ..isAntiAlias = false
..style = PaintingStyle.stroke;
int index = 0; int index = 0;
Paint? listPaint; Paint? listPaint;
@ -126,9 +133,9 @@ class PaintTest extends CustomPainter {
int used = 0; int used = 0;
for (index = 0; index < waveData.length; index++) { for (index = 0; index < waveData.length; index++) {
final (Paint curPaint, Offset p1) = switch (waveData[index]) { final (Paint curPaint, Offset p1) = switch (waveData[index]) {
< 0 => (paintPos, Offset(x, halfHeight * (1 - waveData[index] / 32768))), < 0 => (paintPos, Offset(x, halfHeight * (1 - waveData[index] / 32768))),
> 0 => (paintNeg, Offset(x, halfHeight * (1 - waveData[index] / 32767))), > 0 => (paintNeg, Offset(x, halfHeight * (1 - waveData[index] / 32767))),
_ => (paintZero, Offset(x, halfHeight + 1)), _ => (paintZero, Offset(x, halfHeight + 1)),
}; };
final Offset p0 = Offset(x, halfHeight); final Offset p0 = Offset(x, halfHeight);
if (consolidate) { if (consolidate) {
@ -160,11 +167,9 @@ class PaintTest extends CustomPainter {
} }
class PaintSomeTest extends CustomPainter { class PaintSomeTest extends CustomPainter {
const PaintSomeTest({ const PaintSomeTest({required this.waveData, int? from, int? to})
required this.waveData, : from = from ?? 0,
int? from, to = to ?? waveData.length;
int? to,
}) : from = from ?? 0, to = to?? waveData.length;
final Int16List waveData; final Int16List waveData;
final int from; final int from;
@ -177,29 +182,32 @@ class PaintSomeTest extends CustomPainter {
const double strokeSize = .5; const double strokeSize = .5;
const double zoomFactor = .5; const double zoomFactor = .5;
final Paint paintPos = Paint() final Paint paintPos =
..color = Colors.pink Paint()
..strokeWidth = strokeSize ..color = Colors.pink
..isAntiAlias = false ..strokeWidth = strokeSize
..style = PaintingStyle.stroke; ..isAntiAlias = false
..style = PaintingStyle.stroke;
final Paint paintNeg = Paint() final Paint paintNeg =
..color = Colors.pink Paint()
..strokeWidth = strokeSize ..color = Colors.pink
..isAntiAlias = false ..strokeWidth = strokeSize
..style = PaintingStyle.stroke; ..isAntiAlias = false
..style = PaintingStyle.stroke;
final Paint paintZero = Paint() final Paint paintZero =
..color = Colors.green Paint()
..strokeWidth = strokeSize ..color = Colors.green
..isAntiAlias = false ..strokeWidth = strokeSize
..style = PaintingStyle.stroke; ..isAntiAlias = false
..style = PaintingStyle.stroke;
for (int index = from; index <= to; index++) { for (int index = from; index <= to; index++) {
final (Paint curPaint, Offset p1) = switch (waveData[index]) { final (Paint curPaint, Offset p1) = switch (waveData[index]) {
< 0 => (paintPos, Offset(x, halfHeight * (1 - waveData[index] / 32768))), < 0 => (paintPos, Offset(x, halfHeight * (1 - waveData[index] / 32768))),
> 0 => (paintNeg, Offset(x, halfHeight * (1 - waveData[index] / 32767))), > 0 => (paintNeg, Offset(x, halfHeight * (1 - waveData[index] / 32767))),
_ => (paintZero, Offset(x, halfHeight + 1)), _ => (paintZero, Offset(x, halfHeight + 1)),
}; };
final Offset p0 = Offset(x, halfHeight); final Offset p0 = Offset(x, halfHeight);
canvas.drawLine(p0, p1, curPaint); canvas.drawLine(p0, p1, curPaint);

View File

@ -10,30 +10,251 @@ import 'package:flutter/widgets.dart';
import 'recorder.dart'; import 'recorder.dart';
const List<int> kTransparentImage = <int>[ const List<int> kTransparentImage = <int>[
0x89, 0x50, 0x4E, 0x47, 0x0D, 0x0A, 0x1A, 0x0A, 0x00, 0x00, 0x00, 0x0D, 0x49, 0x89,
0x48, 0x44, 0x52, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x08, 0x06, 0x50,
0x00, 0x00, 0x00, 0x1F, 0x15, 0xC4, 0x89, 0x00, 0x00, 0x00, 0x06, 0x62, 0x4B, 0x4E,
0x47, 0x44, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0xA0, 0xBD, 0xA7, 0x93, 0x00, 0x47,
0x00, 0x00, 0x09, 0x70, 0x48, 0x59, 0x73, 0x00, 0x00, 0x0B, 0x13, 0x00, 0x00, 0x0D,
0x0B, 0x13, 0x01, 0x00, 0x9A, 0x9C, 0x18, 0x00, 0x00, 0x00, 0x07, 0x74, 0x49, 0x0A,
0x4D, 0x45, 0x07, 0xE6, 0x03, 0x10, 0x17, 0x07, 0x1D, 0x2E, 0x5E, 0x30, 0x9B, 0x1A,
0x00, 0x00, 0x00, 0x0B, 0x49, 0x44, 0x41, 0x54, 0x08, 0xD7, 0x63, 0x60, 0x00, 0x0A,
0x02, 0x00, 0x00, 0x05, 0x00, 0x01, 0xE2, 0x26, 0x05, 0x9B, 0x00, 0x00, 0x00, 0x00,
0x00, 0x49, 0x45, 0x4E, 0x44, 0xAE, 0x42, 0x60, 0x82, 0x00,
0x00,
0x0D,
0x49,
0x48,
0x44,
0x52,
0x00,
0x00,
0x00,
0x01,
0x00,
0x00,
0x00,
0x01,
0x08,
0x06,
0x00,
0x00,
0x00,
0x1F,
0x15,
0xC4,
0x89,
0x00,
0x00,
0x00,
0x06,
0x62,
0x4B,
0x47,
0x44,
0x00,
0xFF,
0x00,
0xFF,
0x00,
0xFF,
0xA0,
0xBD,
0xA7,
0x93,
0x00,
0x00,
0x00,
0x09,
0x70,
0x48,
0x59,
0x73,
0x00,
0x00,
0x0B,
0x13,
0x00,
0x00,
0x0B,
0x13,
0x01,
0x00,
0x9A,
0x9C,
0x18,
0x00,
0x00,
0x00,
0x07,
0x74,
0x49,
0x4D,
0x45,
0x07,
0xE6,
0x03,
0x10,
0x17,
0x07,
0x1D,
0x2E,
0x5E,
0x30,
0x9B,
0x00,
0x00,
0x00,
0x0B,
0x49,
0x44,
0x41,
0x54,
0x08,
0xD7,
0x63,
0x60,
0x00,
0x02,
0x00,
0x00,
0x05,
0x00,
0x01,
0xE2,
0x26,
0x05,
0x9B,
0x00,
0x00,
0x00,
0x00,
0x49,
0x45,
0x4E,
0x44,
0xAE,
0x42,
0x60,
0x82,
]; ];
/// An animated GIF image with 3 1x1 pixel frames (a red, green, and blue /// An animated GIF image with 3 1x1 pixel frames (a red, green, and blue
/// frames). The GIF animates forever, and each frame has a 100ms delay. /// frames). The GIF animates forever, and each frame has a 100ms delay.
const List<int> kAnimatedGif = <int> [ const List<int> kAnimatedGif = <int>[
0x47, 0x49, 0x46, 0x38, 0x39, 0x61, 0x01, 0x00, 0x01, 0x00, 0xa1, 0x03, 0x00, 0x47,
0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0x00, 0xff, 0x00, 0xff, 0xff, 0xff, 0x21, 0x49,
0xff, 0x0b, 0x4e, 0x45, 0x54, 0x53, 0x43, 0x41, 0x50, 0x45, 0x32, 0x2e, 0x30, 0x46,
0x03, 0x01, 0x00, 0x00, 0x00, 0x21, 0xf9, 0x04, 0x00, 0x0a, 0x00, 0xff, 0x00, 0x38,
0x2c, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, 0x02, 0x02, 0x4c, 0x39,
0x01, 0x00, 0x21, 0xf9, 0x04, 0x00, 0x0a, 0x00, 0xff, 0x00, 0x2c, 0x00, 0x00, 0x61,
0x00, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, 0x02, 0x02, 0x54, 0x01, 0x00, 0x21, 0x01,
0xf9, 0x04, 0x00, 0x0a, 0x00, 0xff, 0x00, 0x2c, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00,
0x00, 0x01, 0x00, 0x00, 0x02, 0x02, 0x44, 0x01, 0x00, 0x3b, 0x01,
0x00,
0xa1,
0x03,
0x00,
0x00,
0x00,
0xff,
0xff,
0x00,
0x00,
0x00,
0xff,
0x00,
0xff,
0xff,
0xff,
0x21,
0xff,
0x0b,
0x4e,
0x45,
0x54,
0x53,
0x43,
0x41,
0x50,
0x45,
0x32,
0x2e,
0x30,
0x03,
0x01,
0x00,
0x00,
0x00,
0x21,
0xf9,
0x04,
0x00,
0x0a,
0x00,
0xff,
0x00,
0x2c,
0x00,
0x00,
0x00,
0x00,
0x01,
0x00,
0x01,
0x00,
0x00,
0x02,
0x02,
0x4c,
0x01,
0x00,
0x21,
0xf9,
0x04,
0x00,
0x0a,
0x00,
0xff,
0x00,
0x2c,
0x00,
0x00,
0x00,
0x00,
0x01,
0x00,
0x01,
0x00,
0x00,
0x02,
0x02,
0x54,
0x01,
0x00,
0x21,
0xf9,
0x04,
0x00,
0x0a,
0x00,
0xff,
0x00,
0x2c,
0x00,
0x00,
0x00,
0x00,
0x01,
0x00,
0x01,
0x00,
0x00,
0x02,
0x02,
0x44,
0x01,
0x00,
0x3b,
]; ];
/// Measures expense of constructing Image widgets. /// Measures expense of constructing Image widgets.
@ -47,10 +268,12 @@ class BenchBuildImage extends WidgetRecorder {
return Directionality( return Directionality(
textDirection: TextDirection.ltr, textDirection: TextDirection.ltr,
child: _RotatingWidget( child: _RotatingWidget(
child: Row(children: <Widget>[ child: Row(
Image.memory(Uint8List.fromList(kTransparentImage)), children: <Widget>[
Image.memory(Uint8List.fromList(kAnimatedGif)), Image.memory(Uint8List.fromList(kTransparentImage)),
]), Image.memory(Uint8List.fromList(kAnimatedGif)),
],
),
), ),
); );
} }
@ -71,10 +294,8 @@ class _RotatingWidgetState extends State<_RotatingWidget> with SingleTickerProvi
@override @override
void initState() { void initState() {
super.initState(); super.initState();
controller = AnimationController( controller = AnimationController(duration: const Duration(milliseconds: 200), vsync: this)
duration: const Duration(milliseconds: 200), ..repeat();
vsync: this,
)..repeat();
} }
@override @override

View File

@ -32,8 +32,8 @@ class BenchBuildMaterialCheckbox extends WidgetBuildRecorder {
Row _buildRow() { Row _buildRow() {
_isChecked = switch (_isChecked) { _isChecked = switch (_isChecked) {
null => true, null => true,
true => false, true => false,
false => null, false => null,
}; };

View File

@ -56,9 +56,7 @@ class _InfiniteScrollCardsState extends State<_InfiniteScrollCards> {
offset = widget.initialOffset; offset = widget.initialOffset;
scrollController = ScrollController( scrollController = ScrollController(initialScrollOffset: offset);
initialScrollOffset: offset,
);
// Without the timer the animation doesn't begin. // Without the timer the animation doesn't begin.
Timer.run(() async { Timer.run(() async {
@ -86,10 +84,7 @@ class _InfiniteScrollCardsState extends State<_InfiniteScrollCards> {
height: 100.0, height: 100.0,
child: Card( child: Card(
elevation: 16.0, elevation: 16.0,
child: Text( child: Text('${lipsum[index % lipsum.length]} $index', textAlign: TextAlign.center),
'${lipsum[index % lipsum.length]} $index',
textAlign: TextAlign.center,
),
), ),
); );
}, },

View File

@ -39,10 +39,7 @@ class BenchUpdateManyChildLayers extends SceneBuilderRecorder {
Future<void> setUpAll() async { Future<void> setUpAll() async {
_pictures = <Picture>[]; _pictures = <Picture>[];
viewSize = view.physicalSize; viewSize = view.physicalSize;
cellSize = Size( cellSize = Size(viewSize.width / kColumns, viewSize.height / kRows);
viewSize.width / kColumns,
viewSize.height / kRows,
);
rectSize = cellSize * 0.8; rectSize = cellSize * 0.8;
final Paint paint = Paint()..color = const Color.fromARGB(255, 255, 0, 0); final Paint paint = Paint()..color = const Color.fromARGB(255, 255, 0, 0);
@ -72,11 +69,7 @@ class BenchUpdateManyChildLayers extends SceneBuilderRecorder {
if (shouldRetain) { if (shouldRetain) {
sceneBuilder.addRetained(oldLayer); sceneBuilder.addRetained(oldLayer);
} else { } else {
_layers[layerId] = sceneBuilder.pushOffset( _layers[layerId] = sceneBuilder.pushOffset(wobbleOffsetX, offsetY, oldLayer: oldLayer);
wobbleOffsetX,
offsetY,
oldLayer: oldLayer,
);
sceneBuilder.addPicture(Offset.zero, _pictures[row * kColumns + col]); sceneBuilder.addPicture(Offset.zero, _pictures[row * kColumns + col]);
sceneBuilder.pop(); sceneBuilder.pop();
} }

View File

@ -42,27 +42,24 @@ class BenchClippedOutPictures extends SceneBuilderRecorder {
@override @override
void onDrawFrame(SceneBuilder sceneBuilder) { void onDrawFrame(SceneBuilder sceneBuilder) {
final Size viewSize = view.physicalSize / view.devicePixelRatio; final Size viewSize = view.physicalSize / view.devicePixelRatio;
final Size pictureSize = Size( final Size pictureSize = Size(viewSize.width / kColumns, viewSize.height / kRows);
viewSize.width / kColumns,
viewSize.height / kRows,
);
// Fills a single cell with random text. // Fills a single cell with random text.
void fillCell(int row, int column) { void fillCell(int row, int column) {
sceneBuilder.pushOffset( sceneBuilder.pushOffset(column * pictureSize.width, row * pictureSize.height);
column * pictureSize.width,
row * pictureSize.height,
);
final PictureRecorder pictureRecorder = PictureRecorder(); final PictureRecorder pictureRecorder = PictureRecorder();
final Canvas canvas = Canvas(pictureRecorder); final Canvas canvas = Canvas(pictureRecorder);
canvas.save(); canvas.save();
canvas.drawCircle(Offset(pictureSize.width / 2, pictureSize.height / 2), 5.0, paint); canvas.drawCircle(Offset(pictureSize.width / 2, pictureSize.height / 2), 5.0, paint);
canvas.drawRect(Rect.fromCenter( canvas.drawRect(
center: Offset(pictureSize.width / 2, pictureSize.height / 2), Rect.fromCenter(
width: pictureSize.width / 6, center: Offset(pictureSize.width / 2, pictureSize.height / 2),
height: pictureSize.height / 6, width: pictureSize.width / 6,
), paint); height: pictureSize.height / 6,
),
paint,
);
canvas.restore(); canvas.restore();
final Picture picture = pictureRecorder.endRecording(); final Picture picture = pictureRecorder.endRecording();
sceneBuilder.addPicture(Offset.zero, picture); sceneBuilder.addPicture(Offset.zero, picture);
@ -70,14 +67,13 @@ class BenchClippedOutPictures extends SceneBuilderRecorder {
} }
// Starting with the top-left cell, fill every cell. // Starting with the top-left cell, fill every cell.
sceneBuilder.pushClipRect(Rect.fromCircle( sceneBuilder.pushClipRect(
center: Offset(viewSize.width / 2, viewSize.height / 2), Rect.fromCircle(
radius: math.min(viewSize.width, viewSize.height) / 6, center: Offset(viewSize.width / 2, viewSize.height / 2),
)); radius: math.min(viewSize.width, viewSize.height) / 6,
sceneBuilder.pushOffset( ),
5.0 * math.cos(angle),
5.0 * math.sin(angle),
); );
sceneBuilder.pushOffset(5.0 * math.cos(angle), 5.0 * math.sin(angle));
angle += math.pi / 20; angle += math.pi / 20;
for (int row = 0; row < 10; row++) { for (int row = 0; row < 10; row++) {
for (int column = 0; column < 10; column++) { for (int column = 0; column < 10; column++) {

View File

@ -49,7 +49,12 @@ class BenchDrawRect extends SceneBuilderRecorder {
if (benchmarkPaint) { if (benchmarkPaint) {
final Paint paint = Paint(); final Paint paint = Paint();
final double rowRatio = row / kRows; final double rowRatio = row / kRows;
paint.color = Color.fromARGB(255, (255 * rowRatio).floor(), (255 * col / kColumns).floor(), 255); paint.color = Color.fromARGB(
255,
(255 * rowRatio).floor(),
(255 * col / kColumns).floor(),
255,
);
paint.filterQuality = FilterQuality.values[(FilterQuality.values.length * rowRatio).floor()]; paint.filterQuality = FilterQuality.values[(FilterQuality.values.length * rowRatio).floor()];
paint.strokeCap = StrokeCap.values[(StrokeCap.values.length * rowRatio).floor()]; paint.strokeCap = StrokeCap.values[(StrokeCap.values.length * rowRatio).floor()];
paint.strokeJoin = StrokeJoin.values[(StrokeJoin.values.length * rowRatio).floor()]; paint.strokeJoin = StrokeJoin.values[(StrokeJoin.values.length * rowRatio).floor()];
@ -69,19 +74,13 @@ class BenchDrawRect extends SceneBuilderRecorder {
final Canvas canvas = Canvas(pictureRecorder); final Canvas canvas = Canvas(pictureRecorder);
final Size viewSize = view.physicalSize; final Size viewSize = view.physicalSize;
final Size cellSize = Size( final Size cellSize = Size(viewSize.width / kColumns, viewSize.height / kRows);
viewSize.width / kColumns,
viewSize.height / kRows,
);
final Size rectSize = cellSize * 0.8; final Size rectSize = cellSize * 0.8;
for (int row = 0; row < kRows; row++) { for (int row = 0; row < kRows; row++) {
canvas.save(); canvas.save();
for (int col = 0; col < kColumns; col++) { for (int col = 0; col < kColumns; col++) {
canvas.drawRect( canvas.drawRect(Offset((wobbleCounter - 5).abs(), 0) & rectSize, makePaint(row, col));
Offset((wobbleCounter - 5).abs(), 0) & rectSize,
makePaint(row, col),
);
canvas.translate(cellSize.width, 0); canvas.translate(cellSize.width, 0);
} }
canvas.restore(); canvas.restore();

View File

@ -43,7 +43,7 @@ class BenchDynamicClipOnStaticPicture extends SceneBuilderRecorder {
'Bad combination of constant values kRowHeight, kRows, and ' 'Bad combination of constant values kRowHeight, kRows, and '
'kScrollData. With these numbers there is risk that the picture ' 'kScrollData. With these numbers there is risk that the picture '
'will scroll out of the clip entirely. To fix the issue reduce ' 'will scroll out of the clip entirely. To fix the issue reduce '
'kScrollDelta, or increase either kRows or kRowHeight.' 'kScrollDelta, or increase either kRows or kRowHeight.',
); );
} }
@ -52,10 +52,7 @@ class BenchDynamicClipOnStaticPicture extends SceneBuilderRecorder {
final PictureRecorder pictureRecorder = PictureRecorder(); final PictureRecorder pictureRecorder = PictureRecorder();
final Canvas canvas = Canvas(pictureRecorder); final Canvas canvas = Canvas(pictureRecorder);
viewSize = view.physicalSize / view.devicePixelRatio; viewSize = view.physicalSize / view.devicePixelRatio;
clipSize = Size( clipSize = Size(viewSize.width / 2, viewSize.height / 5);
viewSize.width / 2,
viewSize.height / 5,
);
final double cellWidth = viewSize.width / kColumns; final double cellWidth = viewSize.width / kColumns;
final List<Paragraph> paragraphs = generateLaidOutParagraphs( final List<Paragraph> paragraphs = generateLaidOutParagraphs(
@ -72,12 +69,7 @@ class BenchDynamicClipOnStaticPicture extends SceneBuilderRecorder {
for (int column = 0; column < kColumns; column += 1) { for (int column = 0; column < kColumns; column += 1) {
final double left = cellWidth * column; final double left = cellWidth * column;
canvas.save(); canvas.save();
canvas.clipRect(Rect.fromLTWH( canvas.clipRect(Rect.fromLTWH(left, yOffset, cellWidth, 20.0));
left,
yOffset,
cellWidth,
20.0,
));
canvas.drawParagraph( canvas.drawParagraph(
paragraphs[paragraphCounter % paragraphs.length], paragraphs[paragraphCounter % paragraphs.length],
Offset(left, yOffset), Offset(left, yOffset),

View File

@ -19,10 +19,7 @@ import 'recorder.dart';
// but the browser's WebCodecs API is asynchronous running on a separate thread // but the browser's WebCodecs API is asynchronous running on a separate thread
// and does not jank. However, the benchmark result may be the same. // and does not jank. However, the benchmark result may be the same.
class BenchImageDecoding extends RawRecorder { class BenchImageDecoding extends RawRecorder {
BenchImageDecoding() : super( BenchImageDecoding() : super(name: benchmarkName, useCustomWarmUp: true);
name: benchmarkName,
useCustomWarmUp: true,
);
static const String benchmarkName = 'bench_image_decoding'; static const String benchmarkName = 'bench_image_decoding';
@ -62,8 +59,7 @@ class BenchImageDecoding extends RawRecorder {
Future<void> body(Profile profile) async { Future<void> body(Profile profile) async {
await profile.recordAsync('recordImageDecode', () async { await profile.recordAsync('recordImageDecode', () async {
final List<Future<void>> allDecodes = <Future<void>>[ final List<Future<void>> allDecodes = <Future<void>>[
for (final Uint8List data in _imageData) for (final Uint8List data in _imageData) _decodeImage(data),
_decodeImage(data),
]; ];
await Future.wait(allDecodes); await Future.wait(allDecodes);
}, reported: true); }, reported: true);
@ -84,7 +80,7 @@ Future<void> _decodeImage(Uint8List data) async {
if (codec.frameCount < decodeFrameCount) { if (codec.frameCount < decodeFrameCount) {
throw Exception( throw Exception(
'Test image contains too few frames for this benchmark (${codec.frameCount}). ' 'Test image contains too few frames for this benchmark (${codec.frameCount}). '
'Choose a test image with at least $decodeFrameCount frames.' 'Choose a test image with at least $decodeFrameCount frames.',
); );
} }
for (int i = 0; i < decodeFrameCount; i++) { for (int i = 0; i < decodeFrameCount; i++) {

View File

@ -39,7 +39,9 @@ class BenchMaterial3Semantics extends WidgetBuildRecorder {
final AggregatedTimings timings = FlutterTimeline.debugCollect(); final AggregatedTimings timings = FlutterTimeline.debugCollect();
final AggregatedTimedBlock semanticsBlock = timings.getAggregated('SEMANTICS'); final AggregatedTimedBlock semanticsBlock = timings.getAggregated('SEMANTICS');
final AggregatedTimedBlock getFragmentBlock = timings.getAggregated('Semantics.GetFragment'); final AggregatedTimedBlock getFragmentBlock = timings.getAggregated('Semantics.GetFragment');
final AggregatedTimedBlock compileChildrenBlock = timings.getAggregated('Semantics.compileChildren'); final AggregatedTimedBlock compileChildrenBlock = timings.getAggregated(
'Semantics.compileChildren',
);
profile!.addTimedBlock(semanticsBlock, reported: true); profile!.addTimedBlock(semanticsBlock, reported: true);
profile!.addTimedBlock(getFragmentBlock, reported: true); profile!.addTimedBlock(getFragmentBlock, reported: true);
profile!.addTimedBlock(compileChildrenBlock, reported: true); profile!.addTimedBlock(compileChildrenBlock, reported: true);
@ -89,7 +91,9 @@ class BenchMaterial3ScrollSemantics extends WidgetRecorder {
final AggregatedTimings timings = FlutterTimeline.debugCollect(); final AggregatedTimings timings = FlutterTimeline.debugCollect();
final AggregatedTimedBlock semanticsBlock = timings.getAggregated('SEMANTICS'); final AggregatedTimedBlock semanticsBlock = timings.getAggregated('SEMANTICS');
final AggregatedTimedBlock getFragmentBlock = timings.getAggregated('Semantics.GetFragment'); final AggregatedTimedBlock getFragmentBlock = timings.getAggregated('Semantics.GetFragment');
final AggregatedTimedBlock compileChildrenBlock = timings.getAggregated('Semantics.compileChildren'); final AggregatedTimedBlock compileChildrenBlock = timings.getAggregated(
'Semantics.compileChildren',
);
profile!.addTimedBlock(semanticsBlock, reported: true); profile!.addTimedBlock(semanticsBlock, reported: true);
profile!.addTimedBlock(getFragmentBlock, reported: true); profile!.addTimedBlock(getFragmentBlock, reported: true);
profile!.addTimedBlock(compileChildrenBlock, reported: true); profile!.addTimedBlock(compileChildrenBlock, reported: true);
@ -140,8 +144,6 @@ class _ScrollTestState extends State<_ScrollTest> with SingleTickerProviderState
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
return SingleColumnMaterial3Components( return SingleColumnMaterial3Components(scrollController: scrollController);
scrollController: scrollController,
);
} }
} }

View File

@ -23,10 +23,7 @@ class _NestedMouseRegion extends StatelessWidget {
Widget build(BuildContext context) { Widget build(BuildContext context) {
Widget current = child; Widget current = child;
for (int i = 0; i < nests; i++) { for (int i = 0; i < nests; i++) {
current = MouseRegion( current = MouseRegion(onEnter: (_) {}, child: child);
onEnter: (_) {},
child: child,
);
} }
return current; return current;
} }
@ -90,25 +87,26 @@ class BenchMouseRegionGridHover extends WidgetRecorder {
itemCount: rowsCount, itemCount: rowsCount,
cacheExtent: rowsCount * containerSize, cacheExtent: rowsCount * containerSize,
physics: const ClampingScrollPhysics(), physics: const ClampingScrollPhysics(),
itemBuilder: (BuildContext context, int rowIndex) => _NestedMouseRegion( itemBuilder:
nests: 10, (BuildContext context, int rowIndex) => _NestedMouseRegion(
child: Row( nests: 10,
children: List<Widget>.generate( child: Row(
columnsCount, children: List<Widget>.generate(
(int columnIndex) => _NestedMouseRegion( columnsCount,
nests: 10, (int columnIndex) => _NestedMouseRegion(
child: Container( nests: 10,
decoration: BoxDecoration( child: Container(
border: _getBorder(columnIndex, rowIndex), decoration: BoxDecoration(
color: Color.fromARGB(255, rowIndex * 20 % 256, 127, 127), border: _getBorder(columnIndex, rowIndex),
color: Color.fromARGB(255, rowIndex * 20 % 256, 127, 127),
),
width: containerSize,
height: containerSize,
),
), ),
width: containerSize,
height: containerSize,
), ),
), ),
), ),
),
),
), ),
), ),
), ),
@ -148,6 +146,7 @@ class _Tester {
kind: PointerDeviceKind.mouse, kind: PointerDeviceKind.mouse,
); );
} }
TestGesture? _gesture; TestGesture? _gesture;
Duration currentTime = Duration.zero; Duration currentTime = Duration.zero;

View File

@ -65,22 +65,23 @@ class BenchMouseRegionGridScroll extends WidgetRecorder {
itemCount: rowsCount, itemCount: rowsCount,
cacheExtent: rowsCount * containerSize, cacheExtent: rowsCount * containerSize,
physics: const ClampingScrollPhysics(), physics: const ClampingScrollPhysics(),
itemBuilder: (BuildContext context, int rowIndex) => Row( itemBuilder:
children: List<Widget>.generate( (BuildContext context, int rowIndex) => Row(
columnsCount, children: List<Widget>.generate(
(int columnIndex) => MouseRegion( columnsCount,
onEnter: (_) {}, (int columnIndex) => MouseRegion(
child: Container( onEnter: (_) {},
decoration: BoxDecoration( child: Container(
border: _getBorder(columnIndex, rowIndex), decoration: BoxDecoration(
color: Color.fromARGB(255, rowIndex * 20 % 256, 127, 127), border: _getBorder(columnIndex, rowIndex),
color: Color.fromARGB(255, rowIndex * 20 % 256, 127, 127),
),
width: containerSize,
height: containerSize,
),
), ),
width: containerSize,
height: containerSize,
), ),
), ),
),
),
), ),
), ),
), ),
@ -120,6 +121,7 @@ class _Tester {
kind: PointerDeviceKind.mouse, kind: PointerDeviceKind.mouse,
); );
} }
TestGesture? _gesture; TestGesture? _gesture;
Duration currentTime = Duration.zero; Duration currentTime = Duration.zero;

Some files were not shown because too many files have changed in this diff Show More