Skip to content

Instantly share code, notes, and snippets.

@austinstoker
Created July 9, 2025 17:30
Show Gist options
  • Save austinstoker/5ae30b50e99ed909b5d53af7cbe777b3 to your computer and use it in GitHub Desktop.
Save austinstoker/5ae30b50e99ed909b5d53af7cbe777b3 to your computer and use it in GitHub Desktop.
Zooming and reorderable list
import 'package:flutter/material.dart';
void main() {
runApp(const MyApp());
}
class MyApp extends StatelessWidget {
const MyApp({super.key});
@override
Widget build(BuildContext context) {
return MaterialApp(home: const ZoomableReorderableList());
}
}
class ZoomableReorderableList extends StatefulWidget {
const ZoomableReorderableList({super.key});
@override
_ZoomableReorderableListState createState() =>
_ZoomableReorderableListState();
}
class _ZoomableReorderableListState extends State<ZoomableReorderableList> {
final List<String> _items = List.generate(10, (index) => 'Item $index');
double _zoomScale = 1.0; // Initial zoom level
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: const Text('Zoomable Reorderable List'),
actions: [
IconButton(
icon: const Icon(Icons.zoom_in),
onPressed: () {
setState(() {
_zoomScale = (_zoomScale + 0.2).clamp(0.5, 2.0);
});
},
),
IconButton(
icon: const Icon(Icons.zoom_out),
onPressed: () {
setState(() {
_zoomScale = (_zoomScale - 0.2).clamp(0.5, 2.0);
});
},
),
],
),
body: SingleChildScrollView(
child: Center(
child: Transform.scale(
scale: _zoomScale,
// Align the transform to prevent offset issues
alignment: Alignment.topCenter,
child: Container(
// Constrain width to prevent overflow
constraints: BoxConstraints(
maxWidth: MediaQuery.of(context).size.width / _zoomScale,
),
child: ReorderableListView(
shrinkWrap:
true, // Ensure the list fits within the scaled container
physics:
const NeverScrollableScrollPhysics(), // Disable inner scroll
onReorder: (oldIndex, newIndex) {
setState(() {
if (newIndex > oldIndex) {
newIndex -= 1;
}
final item = _items.removeAt(oldIndex);
_items.insert(newIndex, item);
});
},
proxyDecorator: (child, index, animation) {
// Customize the dragged item's appearance
return AnimatedBuilder(
animation: animation,
builder: (context, child) {
final animValue = Curves.easeInOut.transform(
animation.value,
);
return Transform.scale(
scale: 1.0, // Keep dragged item at normal scale
child: Material(
elevation: 4.0,
borderRadius: BorderRadius.circular(8),
shadowColor: Colors.black54,
child: ClipRRect(
borderRadius: BorderRadius.circular(8),
child: child,
),
),
);
},
child: child,
);
},
children: _items.map((item) {
return Card(
key: ValueKey(item), // Unique key for each item
margin: const EdgeInsets.symmetric(
vertical: 4,
horizontal: 8,
),
child: ListTile(title: Text(item)),
);
}).toList(),
),
),
),
),
),
);
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment