Last active
June 30, 2020 23:35
-
-
Save flar/5f34fff7bea958ca1175d196de0fe617 to your computer and use it in GitHub Desktop.
Variation of image animation benchmark used in https://github.com/nazarcybulskij/UI_benchmark. This version uses RepaintBoundary widgets around the Image assets to avoid reconstructing and repainting them on every frame.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import 'package:flutter/material.dart'; | |
void main() { | |
runApp(MyApp()); | |
} | |
class MyApp extends StatelessWidget { | |
// This widget is the root of your application. | |
@override | |
Widget build(BuildContext context) { | |
return MaterialApp( | |
showPerformanceOverlay: false, | |
title: 'Flutter Demo', | |
theme: ThemeData( | |
primarySwatch: Colors.blue, | |
visualDensity: VisualDensity.adaptivePlatformDensity, | |
), | |
home: MyHomePage(title: 'Flutter Demo Home Page'), | |
); | |
} | |
} | |
class MyHomePage extends StatefulWidget { | |
MyHomePage({Key key, this.title}) : super(key: key); | |
final String title; | |
@override | |
_MyHomePageState createState() => _MyHomePageState(); | |
} | |
class _MyHomePageState extends State<MyHomePage> with SingleTickerProviderStateMixin { | |
AnimationController animationController; | |
@override | |
void initState() { | |
super.initState(); | |
animationController = new AnimationController( | |
vsync: this, | |
duration: new Duration(seconds: 5), | |
); | |
animationController.repeat(); | |
} | |
@override | |
void dispose() { | |
animationController.dispose(); | |
super.dispose(); | |
} | |
@override | |
void didChangeDependencies() { | |
var height = MediaQuery.of(context).size.width/10; | |
var width = height; | |
for (var index = 0; index < 10; index++) { | |
precacheImage( Image.asset( | |
GridRotateItem.getImage(index), | |
height: height, | |
width: width, | |
cacheHeight: height.floor(), | |
cacheWidth: width.floor(), | |
fit: BoxFit.cover, | |
).image, context); | |
} | |
super.didChangeDependencies(); | |
} | |
@override | |
Widget build(BuildContext context) { | |
return Scaffold( | |
body: GridView.builder( | |
itemCount: 200, | |
gridDelegate: SliverGridDelegateWithFixedCrossAxisCount(crossAxisCount: 10), | |
itemBuilder: (context, index) { | |
var animateIndex = index % 3; | |
if(animateIndex == 0 ){ | |
return GridRotateItem(index: index, animation: animationController,); | |
} | |
if(animateIndex == 1 ){ | |
return GridFadeItem(index: index, animation: animationController,); | |
} | |
return GridScaleItem(index: index, animation: animationController,); | |
} | |
) | |
); | |
} | |
} | |
class GridRotateItem extends StatefulWidget { | |
final int index; | |
final Animation animation; | |
const GridRotateItem({Key key, this.index, this.animation}) : super(key: key); | |
@override | |
_GridRotateItemState createState() => _GridRotateItemState(); | |
static getImage(index){ | |
var url = 'assets/images/${index % 20}.jpeg'; | |
return url; | |
} | |
} | |
class _GridRotateItemState extends State<GridRotateItem> with SingleTickerProviderStateMixin { | |
double height; | |
double width; | |
@override | |
void didChangeDependencies() { | |
height = MediaQuery.of(context).size.width/10; | |
width = height; | |
super.didChangeDependencies(); | |
} | |
@override | |
Widget build(BuildContext context) { | |
return RotationTransition( | |
turns: Tween(begin: 0.0, end: 1.0).animate(widget.animation), | |
child: RepaintBoundary( | |
child: Image.asset( | |
GridRotateItem.getImage(widget.index), | |
height: height, | |
width: width, | |
cacheHeight: height.floor(), | |
cacheWidth: width.floor(), | |
fit: BoxFit.cover, | |
), | |
), | |
); | |
} | |
} | |
class GridFadeItem extends StatefulWidget { | |
final int index; | |
final Animation animation; | |
const GridFadeItem({Key key, this.index, this.animation}) : super(key: key); | |
@override | |
_GridFadeItemState createState() => _GridFadeItemState(); | |
static getImage(index){ | |
var url = 'assets/images/${index % 20}.jpeg'; | |
return url; | |
} | |
} | |
class _GridFadeItemState extends State<GridFadeItem> with SingleTickerProviderStateMixin { | |
double height; | |
double width; | |
@override | |
void didChangeDependencies() { | |
height = MediaQuery.of(context).size.width/10; | |
width = height; | |
super.didChangeDependencies(); | |
} | |
@override | |
Widget build(BuildContext context) { | |
return FadeTransition( | |
opacity: Tween(begin: 0.0, end: 1.0).animate(widget.animation), | |
child: RepaintBoundary( | |
child: Image.asset( | |
GridFadeItem.getImage(widget.index), | |
height: height, | |
width: width, | |
cacheHeight: height.floor(), | |
cacheWidth: width.floor(), | |
fit: BoxFit.cover, | |
), | |
), | |
); | |
} | |
} | |
class GridScaleItem extends StatefulWidget { | |
final int index; | |
final Animation animation; | |
const GridScaleItem({Key key, this.index, this.animation}) : super(key: key); | |
@override | |
_GridScaleItemState createState() => _GridScaleItemState(); | |
static getImage(index){ | |
var url = 'assets/images/${index % 20}.jpeg'; | |
return url; | |
} | |
} | |
class _GridScaleItemState extends State<GridScaleItem> with SingleTickerProviderStateMixin { | |
double height; | |
double width; | |
@override | |
void didChangeDependencies() { | |
height = MediaQuery.of(context).size.width/10; | |
width = height; | |
super.didChangeDependencies(); | |
} | |
@override | |
Widget build(BuildContext context) { | |
return ScaleTransition( | |
scale: Tween(begin: 0.0, end: 1.0).animate(widget.animation), | |
child: RepaintBoundary( | |
child: Image.asset( | |
GridScaleItem.getImage(widget.index), | |
height: width, | |
width: height, | |
cacheHeight: height.floor(), | |
cacheWidth: width.floor(), | |
fit: BoxFit.cover, | |
), | |
), | |
); | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment