Skip to content

Instantly share code, notes, and snippets.

@iamSahdeep
Last active July 12, 2021 12:28
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save iamSahdeep/9272d79feea33d29be64eb45d48b4ae1 to your computer and use it in GitHub Desktop.
Save iamSahdeep/9272d79feea33d29be64eb45d48b4ae1 to your computer and use it in GitHub Desktop.
AnimatedGrid to convert Grid into List with Animation. Somewhat like this : https://i.stack.imgur.com/HtR9K.gif
// AnimatedGrid : Transforming Grid to List
// Somewhat like this : https://i.stack.imgur.com/HtR9K.gif
import 'package:flutter/material.dart';
void main() {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: MyHomePage(title: 'Flutter Demo Home Page'),
);
}
}
class MyHomePage extends StatefulWidget {
MyHomePage({Key? key, required this.title}) : super(key: key);
final String title;
@override
_MyHomePageState createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
int _column = 1;
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text(widget.title),
),
body: SingleChildScrollView(
child: AnimatedGrid<String>(
itemHeight: 100,
columns: _column,
items: [
'1',
'2',
'3',
'4',
'5',
'6',
'7',
'8',
'9',
'10',
'11',
'12',
'13',
'14',
'15',
'16',
'17',
'18',
'19',
'20',
'21',
'22',
'23',
'24'
],
keyBuilder: (_) => ValueKey(_),
builder: (ctx, item, details) {
return Container(
color: Colors.red.withOpacity(int.parse(item) / 30),
child: Center(
child: Text(item),
),
);
},
),
),
floatingActionButton: FloatingActionButton(
onPressed: () {
setState(() {
_column = _column == 1 ? 2 : 1;
});
},
tooltip: 'lol',
child: Icon(Icons.check),
), // This trailing comma makes auto-formatting nicer for build methods.
);
}
}
typedef AnimatedGridBuilder<T> = Widget Function(
BuildContext, T item, AnimatedGridDetails details);
class AnimatedGrid<T> extends StatelessWidget {
const AnimatedGrid({
Key? key,
required this.itemHeight,
required this.items,
required this.keyBuilder,
required this.builder,
this.columns = 2,
this.duration = const Duration(milliseconds: 750),
this.curve = Curves.easeInOut,
}) : super(key: key);
/// The grid items. Should all be the same height.
final List<T> items;
/// Construct keys given the item provided. Each key must be unique.
final Key Function(T item) keyBuilder;
/// Build a widget given a context, the current item, and the column and row index.
final AnimatedGridBuilder<T> builder;
/// The number of columns wide to display.
final int columns;
/// The height of each child.
final double itemHeight;
/// The duration of the sort animation.
final Duration duration;
/// The curve of the sort animation.
final Curve curve;
static int _rows(int columns, int count) => (count / columns).ceil();
static List<int> gridIndicies(int index, int columns, int count) {
final rows = _rows(columns, count);
final maxItemsForGridSize = columns * rows;
final yIndex = (index / maxItemsForGridSize * rows).floor();
final xIndex = index % columns;
return [xIndex, yIndex];
}
@override
Widget build(BuildContext context) {
return LayoutBuilder(
builder: (context, constraints) {
assert(constraints.hasBoundedWidth);
assert(constraints.hasBoundedHeight == false);
final width = constraints.maxWidth;
final count = items.length;
final itemWidth = width / columns;
final rows = _rows(columns, count);
final gridHeight = rows * itemHeight;
return AnimatedContainer(
duration: duration,
height: gridHeight,
width: itemWidth * columns,
child: Stack(
alignment: Alignment.topLeft,
children: [
for (var i = 0; i <= items.length - 1; i++)
Builder(
key: keyBuilder(items[i]),
builder: (context) {
final item = items[i];
final indicies = gridIndicies(i, columns, count);
assert(indicies.length == 2);
final xIndex = indicies.first;
final yIndex = indicies.last;
final offset =
Offset(xIndex * itemWidth, yIndex * itemHeight);
return TweenAnimationBuilder(
tween: Tween<Offset>(end: offset),
duration: duration,
curve: curve,
builder: (context, Offset offset, child) {
print(offset);
return Transform.translate(
offset: offset,
child: child,
);
},
child: AnimatedContainer(
duration: duration,
height: itemHeight,
width: itemWidth,
child: builder(
context,
item,
AnimatedGridDetails(
index: i,
columnIndex: xIndex,
rowIndex: yIndex,
columns: columns,
rows: rows,
),
),
),
);
},
),
],
),
);
},
);
}
}
class AnimatedGridDetails {
/// A collection of details currently being used by [AnimatedGrid]
AnimatedGridDetails({
required this.index,
required this.columnIndex,
required this.rowIndex,
required this.columns,
required this.rows,
});
/// The current index
final int index;
/// The current column index
final int columnIndex;
/// The current row index
final int rowIndex;
/// The number of columns
final int columns;
/// The number of rows
final int rows;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment