Reputation: 328
I have a ReorderableListView, and I'm using proxyDecorator
to detect when an item starts being dragged and then adjust its height, and the height of the underlying Widget which is actually present in ListView (as I assume the widget returned by proxyDecorator is just used to show what is being dragged.) The issue is that the 'space' in the list where the dragged item was, or is being moved to, remains its original size, rather than reflecting the new size of the widget. Once the dragged item is placed, if I disable the code to return it to it's original size, the rest of the listview bunches up to reflect the new size. But I want this to happen as soon as the drag begins. Is this possible? I have tried using a setState
call in the proxyDecorator
, but this causes an error with triggering a rebuild during a rebuild.
Upvotes: 3
Views: 2819
Reputation: 934
You can achieve it smoothly with proxyDecorator
member of ReorderableListView
. Check the code below:
proxyDecorator: (child, index, animation) {
return Material(
color: Colors.transparent,
child: ScaleTransition(
scale: animation.drive(
Tween<double>(begin: 1, end: 1.1).chain(
CurveTween(curve: Curves.linear),
),
),
child: child,
),
);
},
If you want to scale down the widget instead of scaling up when dragging starts, you should change the end
value to a smaller value, like 0.8
.
Upvotes: 1
Reputation: 36323
I'm not sure what you meant by proxy decorator
, but if you just want to resize an item when it's being dragged, it can be done.
Obviously this is just a quick demo, lots of edge cases are not tested. But if you are interested, here's the full source code used in the above demo:
import 'package:flutter/material.dart';
void main() {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
const MyApp({Key? key}) : super(key: key);
@override
Widget build(BuildContext context) {
return MaterialApp(
home: MyHomePage(),
);
}
}
class MyHomePage extends StatefulWidget {
const MyHomePage({Key? key}) : super(key: key);
@override
_MyHomePageState createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
final colors = [
Colors.red,
Colors.blue,
Colors.green,
Colors.orange,
Colors.purple,
Colors.pink,
Colors.cyan
];
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('ReorderableListView'),
),
body: ReorderableListView(
children: colors
.map((color) => Box(
key: ValueKey(color),
color: color,
))
.toList(),
onReorder: (int oldIndex, int newIndex) {
if (newIndex > oldIndex) newIndex--;
setState(() {
final color = colors.removeAt(oldIndex);
colors.insert(newIndex, color);
});
},
),
);
}
}
class Box extends StatefulWidget {
final Color color;
const Box({Key? key, required this.color}) : super(key: key);
@override
_BoxState createState() => _BoxState();
}
class _BoxState extends State<Box> {
bool _big = false;
@override
Widget build(BuildContext context) {
return GestureDetector(
onTapDown: (_) => setState(() => _big = true),
onTapCancel: () => setState(() => _big = false),
child: AnimatedContainer(
duration: Duration(milliseconds: 200),
height: _big ? 100 : 50,
margin: EdgeInsets.all(4.0),
color: widget.color,
),
);
}
}
Upvotes: 3