Closed NathanFlorins closed 1 year ago
Hello @NathanFlorins
It is possible to use GridView.builder
. But I recommend to use version 5.0.0-dev.3
, because at this version I support GridView.builder
.
In my example app, I added also a part for GridView.builder
:
...
case ReorderableType.gridViewBuilder:
return ReorderableBuilder.builder(
key: Key(_gridViewKey.toString()),
onReorder: _handleReorder,
lockedIndices: lockedIndices,
onDragStarted: () {
const snackBar = SnackBar(
content: Text('Dragging has started!'),
);
ScaffoldMessenger.of(context).showSnackBar(snackBar);
},
scrollController: _scrollController,
childBuilder: (itemBuilder) {
return GridView.builder(
key: _gridViewKey,
controller: _scrollController,
itemCount: children.length,
itemBuilder: (context, index) {
return itemBuilder(
_getChild(index: index),
index,
);
},
gridDelegate: const SliverGridDelegateWithFixedCrossAxisCount(
crossAxisCount: 4,
mainAxisSpacing: 4,
crossAxisSpacing: 8,
),
);
},
);
...
void _handleReorder(ReorderedListFunction reorderedListFunction) {
setState(() {
children = reorderedListFunction(children) as List<int>;
});
}
Thank you for your answer, I will test this
Did it work for you? @NathanFlorins
Hello, No I have a bit of trouble setting up, I use the getx system
What I see could be a problem:
Then I would close this issue until you find a bug or something problematic @NathanFlorins And if you need any help, feel free to write
Ok Thank you @karvulf
Hi @karvulf Sorry but i can't drag, Can you tell me what is wrong?
class PublicationList extends StatelessWidget {
UserModel user;
int totalPublications;
PublicationList({
Key? key,
required this.user,
required this.totalPublications,
}) : super(key: key);
ScrollController scrollController = ScrollController();
late PublicationController publicationController;
@override
Widget build(BuildContext context) {
publicationController = Get.find(tag: 'PublicationController#${user.id}');
var reordableKey = GlobalKey();
return ReorderableBuilder.builder(
key: reordableKey,
onReorder: (value) {},
onDragStarted: () {
const snackBar = SnackBar(
content: Text('Dragging has started!'),
);
ScaffoldMessenger.of(context).showSnackBar(snackBar);
},
scrollController: scrollController,
childBuilder: (itemBuilder) {
return GridView.builder(
shrinkWrap: true,
scrollDirection: Axis.vertical,
controller: scrollController,
gridDelegate: const SliverGridDelegateWithFixedCrossAxisCount(
crossAxisCount: 3,
mainAxisSpacing: 1,
crossAxisSpacing: 1,
),
itemCount: publicationController.publicationList.length < totalPublications
? publicationController.publicationList.length + 3
: publicationController.publicationList.length,
itemBuilder: (BuildContext context, int index) {
if (index < publicationController.publicationList.length) {
return InkWell(
key: Key(publicationController.publicationList
.elementAt(index)
.files
.first
.fileUrl),
onTap: () async {
await Get.to(PublicationShow(user, index, totalPublications));
publicationController.update();
//publicationController.refresh();
},
child: Builder(builder: (context) {
PublicationModel currentPublication =
publicationController.publicationList.elementAt(index);
PublicationMediaModel currentFile =
publicationController.publicationList.elementAt(index).files.first;
String cacheKey =
"publication_${currentPublication.id}_files_${currentFile.id}";
return currentFile.type == "image"
? Stack(
children: [
Shimmer.fromColors(
baseColor: Colors.grey.shade300,
highlightColor: Colors.grey.shade100,
child: Container(
color: LGREY,
),
),
CachedNetworkImage(
imageUrl: currentFile.fileUrl,
fit: BoxFit.cover,
height: double.infinity,
width: double.infinity,
cacheKey: cacheKey,
fadeInDuration: Duration.zero,
fadeOutDuration: Duration.zero,
),
],
)
: Container(
color: Colors.black,
child: Stack(
children: [
// Pourquoi passer le contrôleur en paramètres si c'est pour le construire à ce moment ?????? ... A revois
PublicationVideoPlayer(
videoPlayerController:
VideoPlayerController.network(currentFile.fileUrl),
autoPlay: false,
aspectRation: 1 / 1,
showControls: false,
),
const Padding(
padding: EdgeInsets.all(4.0),
child: Icon(Icons.play_circle_outline,
color: Colors.white, size: 15),
)
],
),
);
}));
} else {
if (publicationController.publicationList.length < totalPublications) {
return Shimmer.fromColors(
baseColor: Colors.grey.shade300,
highlightColor: Colors.grey.shade100,
child: Container(
color: LGREY,
),
);
}
}
return const SizedBox();
},
);
},
);
}
}
You declared your global key in build
.
You have to declare it at the top of your widget, where also scrollController
is created.
Also onReorder
is not used, so after reordering your items, it is possible that the reorder will be reset, when the widget rebuilds because you didn't update the order of your items. Also your if-else statement in itemBuilder
could be a problem if you return widgets with no keys.
If you have still issues, let me know it @NathanFlorins
I don't even have an animation to move an item, nothing happens, as if it was a simple gridview
class PublicationList extends StatelessWidget {
UserModel user;
int totalPublications;
PublicationList({
Key? key,
required this.user,
required this.totalPublications,
}) : super(key: key);
ScrollController scrollController = ScrollController();
late PublicationController publicationController;
var reordableKey = GlobalKey();
@override
Widget build(BuildContext context) {
publicationController = Get.find(tag: 'PublicationController#${user.id}');
return ReorderableBuilder.builder(
key: reordableKey,
enableDraggable: true,
onReorder: (value) {},
onDragStarted: () {
const snackBar = SnackBar(
content: Text('Dragging has started!'),
);
ScaffoldMessenger.of(context).showSnackBar(snackBar);
},
scrollController: scrollController,
childBuilder: (itemBuilder) {
return GridView.builder(
shrinkWrap: true,
scrollDirection: Axis.vertical,
controller: scrollController,
gridDelegate: const SliverGridDelegateWithFixedCrossAxisCount(
crossAxisCount: 3,
mainAxisSpacing: 1,
crossAxisSpacing: 1,
),
itemCount: publicationController.publicationList.length < totalPublications
? publicationController.publicationList.length + 3
: publicationController.publicationList.length,
itemBuilder: (BuildContext context, int index) {
if (index < publicationController.publicationList.length) {
return InkWell(
key: Key(publicationController.publicationList
.elementAt(index)
.files
.first
.fileUrl),
onTap: () async {
await Get.to(PublicationShow(user, index, totalPublications));
publicationController.update();
//publicationController.refresh();
},
child: Builder(builder: (context) {
PublicationModel currentPublication =
publicationController.publicationList.elementAt(index);
PublicationMediaModel currentFile =
publicationController.publicationList.elementAt(index).files.first;
String cacheKey =
"publication_${currentPublication.id}_files_${currentFile.id}";
return currentFile.type == "image"
? Stack(
children: [
Shimmer.fromColors(
baseColor: Colors.grey.shade300,
highlightColor: Colors.grey.shade100,
child: Container(
color: LGREY,
),
),
CachedNetworkImage(
imageUrl: currentFile.fileUrl,
fit: BoxFit.cover,
height: double.infinity,
width: double.infinity,
cacheKey: cacheKey,
fadeInDuration: Duration.zero,
fadeOutDuration: Duration.zero,
),
],
)
: Container(
color: Colors.black,
child: Stack(
children: [
// Pourquoi passer le contrôleur en paramètres si c'est pour le construire à ce moment ?????? ... A revois
PublicationVideoPlayer(
videoPlayerController:
VideoPlayerController.network(currentFile.fileUrl),
autoPlay: false,
aspectRation: 1 / 1,
showControls: false,
),
const Padding(
padding: EdgeInsets.all(4.0),
child: Icon(Icons.play_circle_outline,
color: Colors.white, size: 15),
)
],
),
);
}));
} else {
if (publicationController.publicationList.length < totalPublications) {
return Shimmer.fromColors(
key: Key(publicationController.publicationList
.elementAt(index)
.files
.first
.fileUrl),
baseColor: Colors.grey.shade300,
highlightColor: Colors.grey.shade100,
child: Container(
color: LGREY,
),
);
}
}
return SizedBox(key: Key(publicationController.publicationList
.elementAt(index)
.files
.first
.fileUrl));
},
);
},
);
}
}
did you also long pressed the item? the default behavior is to long press the item before the drag started @NathanFlorins
Oh wait there is another strange thing. In my example, I have the following
return ReorderableBuilder.builder(
key: Key(_gridViewKey.toString()),
onReorder: _handleReorder,
lockedIndices: lockedIndices,
onDragStarted: () {
const snackBar = SnackBar(
content: Text('Dragging has started!'),
);
ScaffoldMessenger.of(context).showSnackBar(snackBar);
},
scrollController: _scrollController,
childBuilder: (itemBuilder) {
return GridView.builder(
key: _gridViewKey,
controller: _scrollController,
itemCount: children.length,
itemBuilder: (context, index) {
return itemBuilder(
_getChild(index: index),
index,
);
},
gridDelegate: const SliverGridDelegateWithFixedCrossAxisCount(
crossAxisCount: 4,
mainAxisSpacing: 4,
crossAxisSpacing: 8,
),
);
},
);
I always called itemBuilder
where I add the child and current index. This is also missing in your code @NathanFlorins
Ok that's it thanks a lot ! @karvulf
Glad to hear! @NathanFlorins
Sorry but I still need a little help from you I can't use OrderUpdateEntity in ReorderableBuilder.builder ?
That part changed since the update to 5.0.0
.
Now you get a function that does the reorder process for you, so you just add your list to the function and it returns the list reordered back.
In your case, that would mean, you just do the following:
...
onReorder: (ReorderedListFunction reorderedListFunction) {
final updatedChildren = reorderedListFunction(your_children) as List<Your_Type>;
// do update your children in your controller
},
...
Possible you need a setState
if your controller does not notify the the widget to rebuilt. @NathanFlorins
@karvulf thanks
@karvulf In order not to send the whole list back to the backend to update it, I would like to send only the new index of the item I moved, is it possible to have the new index/rank of an item with this new function?
It would be possible but this solution has also a meaning because you can lock items that should not move. The function orders these items in a correct way that ensures it is ordered correctly. That is the reason why I added the function. I don't think it works well with your solution updating the list in the backend with the old and new index. Is it possible that you just send a list of the ids of your items? Then you wouldn't send so much data. @NathanFlorins
I plan to use this solution, but I would just like to have the index of the item I move, and the index of the place where I move the item @karvulf
Maybe that would a possible way:
If you don't use lockedIndices
, so this list is empty, then the normal reorder process would be possible with the old and new index just by inserting it. I could add another function that would return also return a result in that case.
But if you have a lot of items and tries to reorder them, then I would recommend to use my function otherwise you could reorder the items by yourself.
I will add that to the next update of version 5.0.0-dev.4
. @NathanFlorins
Ok thanks so it is not possible to have the index of the item I modify ?
Maybe with the onDragStarted method? and onDragEnd ?
Thats also possible. Then I will do the following thing:
onDragStarted
will have the index of the item where the drag startedonDragEnd
will have the index of the item when the drag endsI will try to implement that this evening. @NathanFlorins
Keep me posted it would help me a lot if you implement this tonight because I need to finish what I am doing for tomorrow night! Thanks in advance!
Ah well in that case, I will implement this right now @NathanFlorins
I published 5.0.0-dev.4
. You can try to built your solution with that update. I changed the following:
onDragStarted
index
to parameterindex
is the index where the drag startedonDragEnd
index
to parameterindex
is the index where the drag ended@NathanFlorins
Oh already, great it works! Thank you so much you are great !!! @karvulf
No problem 👍 @NathanFlorins
@karvulf Hi, is there a way to return SliverGrid.builder
? I've tried a few methods like warp in SliverToBoxAdapter()
->error: unbounded height.
Currently this is runnable:
NestedScrollView(
headerSliverBuilder: (context, innerBoxIsScrolled) {
return <Widget>[MyWidget1()];
},
body: ReorderableBuilder.builder(childBuilder: (itemBuilder) {
return GridView.builder(
itemBuilder: (context, index) {
return itemBuilder(myWidget(), index);
},
gridDelegate:
SliverGridDelegateWithFixedCrossAxisCount(crossAxisCount: 2),
);
}),
);
but If I write like this then the Error happens which I hardly to solve it. I don't know how to wrap ReorderableBuilder.builder
,
// in StatelessWidget
@override
Widget build(BuildContext context) {
return RefreshIndicator(
onRefresh: () => Future.sync(
() => myGetxController.reset(),
),
child: CustomScrollView(
scrollDirection: Axis.vertical,
// controller: myGetxController.scrollController,
slivers: [
SliverAppBar(
title: MyWidget1(),
floating: true,
flexibleSpace: Placeholder(),
expandedHeight: 200,
),
ReorderableBuilder.builder(
enableDraggable: false,
scrollController: myGetxController.scrollController,
childBuilder: (itemBuilder) {
return SliverGrid.builder(
gridDelegate: SliverGridDelegateWithFixedCrossAxisCount(
crossAxisCount:
(MediaQuery.of(context).size.width / 400).round(),
mainAxisSpacing: 5,
crossAxisSpacing: 5,
childAspectRatio: 3,
),
itemCount: myGetxController.length,
itemBuilder: (context, index) {
return itemBuilder(
PostWidget(post: myGetxController.datas[index], index: index),
index);
},
);
},
)
],
),
);
}
Related Problem: https://stackoverflow.com/questions/71233618/a-renderviewport-expected-a-child-of-type-rendersliver-but-received-a-child-of-t
I've search for questions like "builder in customscrollview" and asked for help from chatGPT, but still can't solve it.
Hi @AClon314 Currently this is not supported. The reason is that I am using some widgets around the GridView that are not supported by slivers. I will open a new issue to support also Slivers, but it could take some time before this works
Opened Issue #99 @AClon314
Hello, is it possible to use a gridview.builder with this plugin? Here is an example of code that I would like to put in place I also use a pagination