-
-
Save austinstoker/5ae30b50e99ed909b5d53af7cbe777b3 to your computer and use it in GitHub Desktop.
Zooming and reorderable list
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(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