I am developing a simple mobile app with Flutter and I have a view like below:
On this page, the profile information section is fixed at the top, while the widgets listing the following sent widgets are in ReorderableListView
.
But there is a problem with this page. If the user grabs a post and drags it up or down the screen, the screen should also move up or down the screen. Currently, only posts that fit on the screen can be swapped. But I want to be able to swap with the ones that are not visible on the screen.
If I remove the top user info field and give ReorderableListView
to the body
field of Scaffold
, I can get what I want, but this time I can't show the user info part. So I can't give ReorderableListView
to the body
field.
View codes:
import 'package:flutter/material.dart';
class PostsView extends StatefulWidget {
const PostsView({super.key});
@override
State<PostsView> createState() => _PostsViewState();
}
class _PostsViewState extends State<PostsView> {
ScrollController scrollController = ScrollController();
@override
Widget build(BuildContext context) {
return Scaffold(
body: SingleChildScrollView(
controller: scrollController,
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
"My Profile",
style: TextStyle(fontSize: 20, fontWeight: FontWeight.bold),
),
Card(
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
crossAxisAlignment: CrossAxisAlignment.center,
children: [
Row(
children: [
CircleAvatar(
radius: 20,
backgroundImage: NetworkImage(
':ANd9GcTfGaPeS62qusTUFyVchOrh_r2cL4_P8-q3bg&s'),
),
SizedBox(width: 10),
Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text('John Doe'),
Text(
"Hello, my name is John. Welcome to my profile."),
Text("Followers: 100"),
Text("Following: 100"),
Text("Posts: 100"),
Text("Comments: 100"),
Text("Likes: 100"),
],
)
],
),
Icon(Icons.more_vert)
],
),
),
SizedBox(height: 20),
ReorderableListView.builder(
shrinkWrap: true,
scrollController: scrollController,
itemExtent: 200,
itemBuilder: (context, index) {
return ReorderableDelayedDragStartListener(
key: ValueKey(index),
index: index,
child: Container(
margin: EdgeInsets.only(bottom: 10),
decoration: BoxDecoration(
color: Colors.grey.shade200,
borderRadius: BorderRadius.circular(10),
border: Border.all(
color: Colors.black,
),
),
child: Column(
children: [
Imagework(
':ANd9GcTfGaPeS62qusTUFyVchOrh_r2cL4_P8-q3bg&s',
width: 100,
height: 100,
),
Text("Post title: $index"),
Text("Post description: $index"),
Text("Post date: $index"),
],
),
),
);
},
itemCount: 20,
onReorder: (oldIndex, newIndex) {
setState(() {});
},
),
],
),
),
);
}
}
(You can try it quickly by pasting the code into the code editor. I didn't write features like onReorder
because it's not important for now, I need to solve the scrolling problem :))
For 2 days I have been trying to solve this problem but I can't. I am grateful in advance for your help.
I am developing a simple mobile app with Flutter and I have a view like below:
On this page, the profile information section is fixed at the top, while the widgets listing the following sent widgets are in ReorderableListView
.
But there is a problem with this page. If the user grabs a post and drags it up or down the screen, the screen should also move up or down the screen. Currently, only posts that fit on the screen can be swapped. But I want to be able to swap with the ones that are not visible on the screen.
If I remove the top user info field and give ReorderableListView
to the body
field of Scaffold
, I can get what I want, but this time I can't show the user info part. So I can't give ReorderableListView
to the body
field.
View codes:
import 'package:flutter/material.dart';
class PostsView extends StatefulWidget {
const PostsView({super.key});
@override
State<PostsView> createState() => _PostsViewState();
}
class _PostsViewState extends State<PostsView> {
ScrollController scrollController = ScrollController();
@override
Widget build(BuildContext context) {
return Scaffold(
body: SingleChildScrollView(
controller: scrollController,
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
"My Profile",
style: TextStyle(fontSize: 20, fontWeight: FontWeight.bold),
),
Card(
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
crossAxisAlignment: CrossAxisAlignment.center,
children: [
Row(
children: [
CircleAvatar(
radius: 20,
backgroundImage: NetworkImage(
'https://encrypted-tbn0.gstatic/images?q=tbn:ANd9GcTfGaPeS62qusTUFyVchOrh_r2cL4_P8-q3bg&s'),
),
SizedBox(width: 10),
Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text('John Doe'),
Text(
"Hello, my name is John. Welcome to my profile."),
Text("Followers: 100"),
Text("Following: 100"),
Text("Posts: 100"),
Text("Comments: 100"),
Text("Likes: 100"),
],
)
],
),
Icon(Icons.more_vert)
],
),
),
SizedBox(height: 20),
ReorderableListView.builder(
shrinkWrap: true,
scrollController: scrollController,
itemExtent: 200,
itemBuilder: (context, index) {
return ReorderableDelayedDragStartListener(
key: ValueKey(index),
index: index,
child: Container(
margin: EdgeInsets.only(bottom: 10),
decoration: BoxDecoration(
color: Colors.grey.shade200,
borderRadius: BorderRadius.circular(10),
border: Border.all(
color: Colors.black,
),
),
child: Column(
children: [
Imagework(
'https://encrypted-tbn0.gstatic/images?q=tbn:ANd9GcTfGaPeS62qusTUFyVchOrh_r2cL4_P8-q3bg&s',
width: 100,
height: 100,
),
Text("Post title: $index"),
Text("Post description: $index"),
Text("Post date: $index"),
],
),
),
);
},
itemCount: 20,
onReorder: (oldIndex, newIndex) {
setState(() {});
},
),
],
),
),
);
}
}
(You can try it quickly by pasting the code into the code editor. I didn't write features like onReorder
because it's not important for now, I need to solve the scrolling problem :))
For 2 days I have been trying to solve this problem but I can't. I am grateful in advance for your help.
Share Improve this question edited Mar 20 at 12:13 Burak Şanlı asked Mar 20 at 12:02 Burak ŞanlıBurak Şanlı 351 silver badge4 bronze badges2 Answers
Reset to default 2To fix this, you could use a CustomScrollView
instead of SingleChildScrollView
and a SliverList
for the user profile section. That way, the ReorderableListView
will work seamlessly with scrolling.
import 'package:flutter/material.dart';
class PostsView extends StatefulWidget {
const PostsView({super.key});
@override
State<PostsView> createState() => _PostsViewState();
}
class _PostsViewState extends State<PostsView> {
final List<int> items = List.generate(20, (index) => index); // Example items
@override
Widget build(BuildContext context) {
return Scaffold(
body: CustomScrollView(
slivers: [
SliverToBoxAdapter(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
"My Profile",
style: TextStyle(fontSize: 20, fontWeight: FontWeight.bold),
),
Card(
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
crossAxisAlignment: CrossAxisAlignment.center,
children: [
Row(
children: [
CircleAvatar(
radius: 20,
backgroundImage: NetworkImage(
'https://encrypted-tbn0.gstatic/images?q=tbn:ANd9GcTfGaPeS62qusTUFyVchOrh_r2cL4_P8-q3bg&s',
),
),
SizedBox(width: 10),
Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text('John Doe'),
Text("Hello, my name is John. Welcome to my profile."),
Text("Followers: 100"),
Text("Following: 100"),
Text("Posts: 100"),
Text("Comments: 100"),
Text("Likes: 100"),
],
),
],
),
Icon(Icons.more_vert),
],
),
),
],
),
),
SliverReorderableList(
itemBuilder: (context, index) {
return Container(
key: ValueKey(items[index]),
margin: EdgeInsets.all(8),
decoration: BoxDecoration(
color: Colors.grey.shade200,
borderRadius: BorderRadius.circular(10),
border: Border.all(
color: Colors.black,
),
),
child: Column(
children: [
Imagework(
'https://encrypted-tbn0.gstatic/images?q=tbn:ANd9GcTfGaPeS62qusTUFyVchOrh_r2cL4_P8-q3bg&s',
width: 100,
height: 100,
),
Text("Post title: ${items[index]}"),
Text("Post description: ${items[index]}"),
],
),
);
},
itemCount: items.length,
onReorder: (oldIndex, newIndex) {
setState(() {
if (newIndex > oldIndex) newIndex -= 1;
final item = items.removeAt(oldIndex);
items.insert(newIndex, item);
});
},
),
],
),
);
}
}
import 'package:flutter/material.dart';
class PostsView extends StatefulWidget {
const PostsView({super.key});
@override
State<PostsView> createState() => _PostsViewState();
}
class _PostsViewState extends State<PostsView> {
final List<String> list = [
"Data1",
"Data2",
"Data3",
"Data4",
"Data5",
"Data6",
"Data7",
"Data8",
"Data9",
"Data10",
"Data11",
"Data12",
"Data13",
"Data14",
"Data15",
"Data16",
"Data17",
"Data18",
"Data19",
"Data20",
];
@override
Widget build(BuildContext context) {
return Scaffold(
body: SafeArea(
child: Column(
children: [
Card(
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
crossAxisAlignment: CrossAxisAlignment.center,
children: [
Row(
children: [
const CircleAvatar(
radius: 20,
backgroundImage: NetworkImage(
'https://encrypted-tbn0.gstatic/images?q=tbn:ANd9GcTfGaPeS62qusTUFyVchOrh_r2cL4_P8-q3bg&s',
),
),
const SizedBox(width: 10),
Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: const [
Text('John Doe'),
Text(
"Hello, my name is John. Welcome to my profile."),
Text("Followers: 100"),
Text("Following: 100"),
Text("Posts: 100"),
Text("Comments: 100"),
Text("Likes: 100"),
],
)
],
),
const Icon(Icons.more_vert),
],
),
),
const SizedBox(height: 20),
Expanded(
child: ReorderableListView.builder(
itemCount: list.length,
onReorder: (oldIndex, newIndex) {
if (newIndex > oldIndex) {
newIndex -= 1;
}
setState(() {
final item = list.removeAt(oldIndex); // Remove item
list.insert(newIndex, item); // Insert at new index
});
},
itemBuilder: (context, index) {
final String productName = list[index];
return Card(
key: ValueKey(productName),
color: Colors.green,
elevation: 1,
margin: const EdgeInsets.all(5),
child: ListTile(
contentPadding: const EdgeInsets.all(5),
title: Text(
productName,
style: const TextStyle(fontSize: 18),
),
),
);
},
),
),
],
),
),
);
}
}