Я отказался от попыток с GridView.Однако я нашел способ получить тот же результат с помощью Stack и SlideTransition:
import 'package:flutter/material.dart';
class HomeScreen extends StatefulWidget {
@override
State<StatefulWidget> createState() {
return _HomeScreenState();
}
}
class _HomeScreenState extends State<HomeScreen> with TickerProviderStateMixin {
String move;
List<Tween> _switchTween = List();
List<Animation> _switchAnim = List();
List<AnimationController> _switchAnimCont = List();
double width;
@override
void initState() {
// Add a tween and a controller for each element
for (int i = 0; i < 5; i++) {
_switchAnimCont.add(AnimationController(
vsync: this,
duration: const Duration(milliseconds: 100),
));
_switchTween.add(Tween<Offset>(begin: Offset.zero, end: Offset(0, 1)));
_switchAnim.add(_switchTween[i].animate(_switchAnimCont[i]));
}
super.initState();
}
@override
Widget build(BuildContext context) {
width = MediaQuery.of(context).size.width/5;
return Stack(
children: <Widget>[
square(0, 0, 0),
square(1, width, 0),
square(2, 2*width, 0),
square(3, 3*width, 0),
square(4, 4*width, 0),
],
);
}
Widget square(int index, double left, double bottom) {
return Positioned(
left: left,
bottom: bottom,
width: width,
height: width,
child: SlideTransition(
position: _switchAnim[index],
child: GestureDetector(
// Figure out swipe's direction
onHorizontalDragUpdate: (drag) {
if (drag.delta.dx > 10) move = 'right';
if (drag.delta.dx < -10) move = 'left';
},
onHorizontalDragEnd: (drag) {
switch(move) {
case 'right' : {moveRight(index); break;}
case 'left' : {moveLeft(index); break;}
}
},
child: Container(
margin: EdgeInsets.all(2),
decoration: BoxDecoration(
color: Colors.white,
borderRadius: BorderRadius.all(Radius.circular(5.0))
),
),
),
),
);
}
void moveRight(int index) {
// Move the grid element that you swiped on
_switchTween[index].end = Offset(1, 0);
_switchAnimCont[index].forward();
// Move the element next to it the opposite way
_switchTween[index+1].end = Offset(-1, 0);
_switchAnimCont[index+1].forward();
// You could need to refresh the corresponding controller to animate again
}
void moveLeft(int index) {
_switchTween[index].end = Offset(-1, 0);
_switchAnimCont[index].forward();
_switchTween[index-1].end = Offset(1, 0);
_switchAnimCont[index-1].forward();
}
}
Это нарисует 5 белых квадратов, и проведя пальцем влево или вправо по одному из них, соответствующий квадрат поменяется местамис одним рядом с ним.Он также может быть расширен для использования по вертикали (при условии добавления новой строки).