Reputation: 93
I am attempting to create a Drag and Drop with a GridView.custom. What I desire to have happen, is that when dragging an item, if it reaches the top or bottom of the screen, the gridview scrolls. Is there a build in way to do that, or is there a work around that has to be implemented. I am using the flutter_staggered_grid_view package in this case.
GridView.custom(
shrinkWrap: true,
primary: false,
scrollDirection: Axis.vertical,
gridDelegate: SliverQuiltedGridDelegate(
crossAxisCount: 4,
mainAxisSpacing: 10,
crossAxisSpacing: 10,
repeatPattern: QuiltedGridRepeatPattern.inverted,
pattern: widget.pattern,
),
childrenDelegate: SliverChildBuilderDelegate(
childCount: widget.children.length,
(context, index) {
var selectedWidget = widget.children[index];
LongPressDraggable<GlobalKey>(
data: selectedWidget.key,
onDragStarted: _onDragStarted,
onDragEnd: _onDragEnd,
feedback:
SizedBox(width: 100, height: 100, child: selectedWidget),
childWhenDragging: Container(),
child: DragTarget<GlobalKey>(
builder: (context, accepted, rejected) => selectedWidget,
onWillAccept: (GlobalKey? accept) {
return true;
},
onAccept: (GlobalKey item) {
int startIndex =
widget.children.indexWhere((x) => x.key == item);
int endIndex = widget.children
.indexWhere((x) => x.key == selectedWidget.key);
widget.onReorder(startIndex, endIndex);
},
),
)
},
),
);
Upvotes: 1
Views: 1220
Reputation: 93
After some research, I cobbled together a method that created the effect I desired.
return Stack(
children: [
renderDraggableGrid(),
_isDragStart
? Align(
alignment: Alignment.topCenter,
child: DragTarget(
builder: (context, accepted, rejected) => Container(
height: 40,
width: double.infinity,
color: Colors.transparent,
),
onWillAccept: (GlobalKey? accept) {
_moveUp();
return false;
},
),
)
: Container(),
_isDragStart
? Align(
alignment: Alignment.bottomCenter,
child: DragTarget(
builder: (context, accepted, rejected) => Container(
height: 40,
width: double.infinity,
color: Colors.transparent,
),
onWillAccept: (GlobalKey? accept) {
_moveDown();
return false;
},
),
)
: Container()
],
);
_moveUp() {
_scrollController!.animateTo(_scrollController!.offset - _gridViewHeight,
curve: Curves.linear, duration: Duration(milliseconds: 500));
}
_moveDown() {
_scrollController!.animateTo(_scrollController!.offset + _gridViewHeight,
curve: Curves.linear, duration: Duration(milliseconds: 500));
}
I also added ClampingScrollPhysics()
to avoid over scrolling. Credit to https://github.com/DevOrbiter/drag_and_drop_gridview/ for giving me the base code.
Upvotes: 3
Reputation: 1
compare Draggable
position of the Y axis in GridView
area.
Here is the sample; Scroll up if Draggle
positions on a top area where is height 20, scroll down if it positions on a bottom area where is height 20.
import 'dart:async';
import 'dart:math';
import 'package:flutter/material.dart';
void main() {
runApp(const MaterialApp(home: MyApp()));
}
class MyApp extends StatefulWidget {
const MyApp({Key? key}) : super(key: key);
@override
State<MyApp> createState() => _MyAppState();
}
class _MyAppState extends State<MyApp> {
final List<int> droppedIndexList = [];
late final ScrollController scrollController;
final GlobalKey gridViewKey = GlobalKey();
void initState() {
super.initState();
scrollController = ScrollController();
Timer.periodic(const Duration(milliseconds: 100), (_) {
if(scrollDirection == 0) {
return;
} else if(scrollDirection == 1) { // scroll down
scrollController.animateTo(
min(scrollController.offset + 20, scrollController.position.maxScrollExtent),
duration: const Duration(milliseconds: 100),
curve: Curves.linear,
);
} else if(scrollDirection == -1) { // scroll up
scrollController.animateTo(
max(scrollController.offset - 20, scrollController.position.minScrollExtent),
duration: const Duration(milliseconds: 100),
curve: Curves.linear,
);
}
});
}
int scrollDirection = 0;
@override
Widget build(BuildContext context) {
return Scaffold(
body: Center(
child: Padding(
padding: const EdgeInsets.symmetric(vertical: 100),
child: SizedBox(
width: 600,
child: Column(
children: [
SizedBox(
height: 200,
child: Center(
child: Draggable(
onDragUpdate: (details) {
final s = gridViewKey.currentContext!.size!;
final p = (gridViewKey.currentContext!.findRenderObject() as RenderBox).globalToLocal(details.globalPosition);
print(p.dy);
if(0 <= p.dy && p.dy <= 20) {
scrollDirection = -1;
} else if(s.height - 20 <= p.dy && p.dy <= s.height) {
scrollDirection = 1;
} else {
scrollDirection = 0;
}
},
data: Colors.black,
feedback: Container(
width: 100,
height: 100,
color: Colors.black,
),
child: Container(
width: 100,
height: 100,
color: Colors.black,
),
),
),
),
Expanded(
child: GridView.builder(
key: gridViewKey,
controller: scrollController,
gridDelegate: const SliverGridDelegateWithFixedCrossAxisCount(
crossAxisCount: 3,
),
itemCount: 300,
itemBuilder: (context, index) {
return DragTarget<Color>(
onAccept: (color) {
setState(() {
droppedIndexList.add(index);
});
},
builder: (BuildContext context, List<Color?> candidateData, List<dynamic> rejectedData) {
return Container(
width: 200,
height: 200,
decoration: BoxDecoration(
border: Border.all(
color: Colors.black,
width: 1,
),
color: droppedIndexList.contains(index) ? Colors.black : Colors.transparent,
),
child: Center(
child: Text(
"$index"
),
),
);
},
);
}
),
),
],
),
),
),
),
);
}
}
Upvotes: 0