我正在测试一个简单的场景:有很多帖子类别,每个类别都有自己的帖子。
我希望能够拖放并重新排序类别,以及特定类别中的帖子。
我想在单个滚动条内显示完全扩展的所有列表。
是的,看起来我需要一个用于所有类别的可重新排序列表视图,以便我可以重新排序它们,并且对于每个类别,另一个可重新排序列表视图用于对该类别中的帖子进行排序。 PS:通过拖动将帖子移动到另一个类别也很棒
我将在下面提供一些我正在尝试但没有成功的代码:
import 'dart:math';
import 'package:flutter/material.dart';
class TmpScreen extends StatefulWidget {
const TmpScreen({super.key});
@override
State<TmpScreen> createState() => _TmpScreenState();
}
class _TmpScreenState extends State<TmpScreen> {
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: const Row(
children: [
Text('Posts'),
],
)),
body: SingleChildScrollView(
child: Container(
height: MediaQuery.of(context).size.height,
padding: const EdgeInsets.all(16),
child: Column(
children: [
Text('All posts'),
const SizedBox(
height: 36,
),
Expanded(
child: ReorderableListView(
onReorder: (oldIndex, newIndex) {
print(
'Reordering post categories $oldIndex -> $newIndex');
},
children: List.generate(postsByCategory.length, (index) {
final postByCategory = postsByCategory[index];
return Column(
key: ValueKey(postByCategory.category),
children: [
Text(postByCategory.category),
Expanded(
child: ReorderableListView(
onReorder: (oldIndex, newIndex) {
print(
'Reordering posts inside category ${postByCategory.category}, $oldIndex -> $newIndex');
},
children: List.generate(
postByCategory.posts.length, (index) {
final post = postByCategory.posts[index];
return Text(
key: ValueKey(post.name),
'Post ${post.name}');
})))
],
);
})),
)
],
)),
),
);
}
}
final postsByCategory =
List.generate(10, (index) => generateRandomPostsByCategory(10));
class PostsByCategory {
final String category;
final List<Post> posts;
PostsByCategory({required this.category, required this.posts});
}
class Post {
final String name;
Post(this.name);
}
String generateRandomString(int length) {
const String chars =
'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789';
Random random = Random();
return String.fromCharCodes(
Iterable.generate(
length,
(_) => chars.codeUnitAt(random.nextInt(chars.length)),
),
);
}
Post generateRandomPost() {
String randomPostName = generateRandomString(10);
return Post(randomPostName);
}
PostsByCategory generateRandomPostsByCategory(int numPosts) {
String randomCategory =
generateRandomString(8); // Generate a random category name
List<Post> randomPosts = List.generate(numPosts, (_) => generateRandomPost());
return PostsByCategory(category: randomCategory, posts: randomPosts);
}
上面的代码根本不渲染。 我可以修复它以进行渲染,但它不起作用,列表没有显示所有项目,而且我不知道如何支持我的用例。
任何 Flutter 专家都可以提供有用的见解吗?
当嵌套像
ReorderableListView
这样的可滚动小部件时,特别是具有相同的滚动方向时,您经常会遇到布局约束问题。发生这种情况是因为 Flutter 无法推断嵌套列表的正确高度/宽度,从而导致渲染问题。
要解决此问题,您需要手动设置每个类别的
ReorderableListView
的高度。高度应考虑类别的标签高度和该类别内帖子的总高度。
此外,最好通过将
physics
设置为 NeverScrollableScrollPhysics
来禁用每个类别中帖子的滚动。
这是代码的简化和更正版本:
import 'package:flutter/material.dart';
void main() => runApp(const MainApp());
class MainApp extends StatelessWidget {
const MainApp({super.key});
@override
Widget build(BuildContext context) {
return MaterialApp(
home: Scaffold(
appBar: AppBar(
title: const Text('All Posts'),
),
body: const PostsView(),
),
);
}
}
class PostsView extends StatefulWidget {
const PostsView({super.key});
@override
State<PostsView> createState() => _PostsViewState();
}
class _PostsViewState extends State<PostsView> {
final _categories = [
PostsByCategory(
category: 'Category 1',
posts: [Post('Post 1'), Post('Post 2'), Post('Post 3')],
),
PostsByCategory(
category: 'Category 2',
posts: [Post('Post 4'), Post('Post 5'), Post('Post 6')],
),
PostsByCategory(
category: 'Category 3',
posts: [Post('Post 7'), Post('Post 8'), Post('Post 9')],
),
];
@override
Widget build(BuildContext context) {
const postHeight = 56.0; // Set a fixed height for each post
const labelHeight = 48.0; // Set a fixed height for each category label
return ReorderableListView.builder(
primary: true,
padding: const EdgeInsets.all(16),
onReorder: (oldIndex, newIndex) {
if (newIndex > oldIndex) newIndex -= 1;
final category = _categories.removeAt(oldIndex);
_categories.insert(newIndex, category);
},
itemCount: _categories.length,
itemBuilder: (_, index) {
final category = _categories[index];
return SizedBox(
key: ValueKey(category.category),
height: (category.posts.length * postHeight) + labelHeight, // Dynamically calculate height based on the number of posts
child: Column(
children: [
SizedBox(
height: labelHeight, // Fixed height for label
child: Center(
child: Text(category.category),
),
),
Expanded(
child: ReorderableListView.builder(
physics: const NeverScrollableScrollPhysics(), // Disable scrolling for the nested list
onReorder: (oldIndex, newIndex) {
if (newIndex > oldIndex) newIndex -= 1;
final post = category.posts.removeAt(oldIndex);
category.posts.insert(newIndex, post);
},
itemCount: category.posts.length,
itemBuilder: (_, index) {
final post = category.posts[index];
return SizedBox(
key: ValueKey(post.name),
height: postHeight, // Fixed height for each post
child: Center(
child: Text(post.name),
),
);
},
),
),
],
),
);
},
);
}
}
class PostsByCategory {
final String category;
final List<Post> posts;
PostsByCategory({required this.category, required this.posts});
}
class Post {
final String name;
Post(this.name);
}