我有一个小部件列表(练习)在我的屏幕上。我想让它使练习是可重新排序的,这样我就可以拖放它们,顺序就会改变。
这是我的完整代码:
import 'dart:collection';
import 'package:flutter/material.dart';
import 'package:workout_app/Screens/Components/Widgets/footer.dart';
class workout_page extends StatefulWidget {
@override
_WorkoutPageState createState() => _WorkoutPageState();
}
class _WorkoutPageState extends State<workout_page>
with TickerProviderStateMixin {
late TabController _tabController;
late PageController _pageController;
TextEditingController _newTabController = TextEditingController();
late var currentPageIndx;
List<String> plans = [];
late String firstplan;
List<Map<String, dynamic>> workoutMap = [
{
'plan_name': 'My First Plan',
'content': [
{
'name': 'My First Workout',
'exercises': [
{
'name': 'Bicep Curl',
'musclesworked': ['bicep', 'tricep']
},
{
'name': 'Preacher Curl',
'musclesworked': ['bicep', 'tricep']
},
{
'name': 'Bicep Curl',
'musclesworked': ['bicep', 'tricep']
},
{
'name': 'Preacher Curl',
'musclesworked': ['bicep', 'tricep']
},
{
'name': 'Bicep Curl',
'musclesworked': ['bicep', 'tricep']
},
{
'name': 'Preacher Curl',
'musclesworked': ['bicep', 'tricep']
},
{
'name': 'Bicep Curl',
'musclesworked': ['bicep', 'tricep']
},
{
'name': 'Preacher Curl',
'musclesworked': ['bicep', 'tricep']
}
]
}
]
},
{
'plan_name': 'My Second Plan',
'content': [
{
'name': 'My Second Workout',
'exercises': [
{
'name': 'POOPY Curl',
'musclesworked': ['bicep', 'tricep']
},
{
'name': 'Preacher Curl',
'musclesworked': ['bicep', 'tricep']
},
{
'name': 'Bicep Curl',
'musclesworked': ['bicep', 'tricep']
},
{
'name': 'Preacher Curl',
'musclesworked': ['bicep', 'tricep']
},
{
'name': 'Bicep Curl',
'musclesworked': ['bicep', 'tricep']
},
{
'name': 'Preacher Curl',
'musclesworked': ['bicep', 'tricep']
},
{
'name': 'Bicep Curl',
'musclesworked': ['bicep', 'tricep']
},
{
'name': 'Preacher Curl',
'musclesworked': ['bicep', 'tricep']
}
]
}
]
},
];
@override
void initState() {
super.initState();
for (var i = 0; i < workoutMap.length; i++) {
plans.add(workoutMap[i]['plan_name']);
}
firstplan = plans[0];
currentPageIndx = 1;
_tabController = TabController(
length: workoutMap[currentPageIndx]['content'].length +
(workoutMap[currentPageIndx]['content'].length < 4 ? 1 : 0),
vsync: this,
);
_pageController = PageController();
}
void _addTab() {
setState(() {
String newTabName = _newTabController.text;
Map<String, Object> newTab = {
'name': newTabName,
'exercises': [],
};
workoutMap[currentPageIndx]['content'].add(newTab);
_newTabController.clear();
_tabController = TabController(
length: workoutMap[currentPageIndx]['content'].length +
(workoutMap[currentPageIndx]['content'].length < 4 ? 1 : 0),
vsync: this,
);
});
}
@override
void dispose() {
super.dispose();
}
@override
Widget build(BuildContext context) {
var size = MediaQuery.of(context).size;
return Container(
child: Material(
color: Colors.green,
child: DefaultTabController(
length: workoutMap[currentPageIndx]['content'].length +
(workoutMap[currentPageIndx]['content'].length < 4 ? 1 : 0),
child: Scaffold(
resizeToAvoidBottomInset: false,
backgroundColor: Color.fromRGBO(79, 79, 79, 1),
body: Stack(
children: [
CustomScrollView(
slivers: [
SliverAppBar(
titleSpacing: 15,
pinned: true,
elevation: 0,
backgroundColor: Color.fromARGB(255, 17, 17, 17),
centerTitle: false,
bottom: PreferredSize(
preferredSize: const Size.fromHeight(40),
child: Column(
children: [
Container(
color: Color.fromARGB(255, 17, 17, 17),
child: Row(
children: [
Spacer(),
Container(
padding: EdgeInsets.symmetric(
horizontal:
10.0), // 1. Padding on the left and right sides
decoration: BoxDecoration(
color: Color.fromARGB(255, 35, 35, 35),
borderRadius: BorderRadius.circular(
3.0), // 2. Circular edges
),
child: ConstrainedBox(
// To3make the entire container smaller
constraints: BoxConstraints(
maxWidth: size.width * .5,
maxHeight: 35),
child: DropdownButtonHideUnderline(
child: DropdownButton<String>(
value: firstplan,
dropdownColor:
Color.fromARGB(255, 35, 35, 35),
isExpanded:
true, // To make sure dropdown appears below
items: plans
.map(
(item) =>
DropdownMenuItem<String>(
value: item,
child: Text(
item,
style: TextStyle(
fontSize: 15,
color: Colors.white,
),
),
),
)
.toList(),
onChanged: (item) {
setState(() {
firstplan = item!;
currentPageIndx =
plans.indexOf(firstplan);
_tabController = TabController(
length: workoutMap[
currentPageIndx]
['content']
.length +
(workoutMap[currentPageIndx]
['content']
.length <
4
? 1
: 0),
vsync: this,
);
});
},
),
),
),
),
SizedBox(width: 10),
Transform.translate(
offset: Offset(0, .3),
child: ElevatedButton(
onPressed: () => print('premium'),
style: ElevatedButton.styleFrom(
primary:
Color.fromARGB(255, 35, 35, 35),
),
child: Text('Go Premium'),
),
),
Spacer()
],
),
),
Container(
decoration: BoxDecoration(
color: Color.fromRGBO(60, 60, 60, 1),
),
child: TabBar(
indicatorColor: Colors.grey,
controller: _tabController,
onTap: (index) {
if (index == _tabController.length - 1 &&
workoutMap[currentPageIndx]['content']
.length <
4) {
_tabController.animateTo(
_tabController.previousIndex);
} else {
_tabController.animateTo(index);
_pageController.jumpToPage(index);
}
},
tabs: [
...workoutMap[currentPageIndx]['content'].map(
(tab) => Tab(
text: tab['name'] as String,
),
),
if (workoutMap[currentPageIndx]['content']
.length <
4)
Container(
width: 40,
height: 40,
alignment: Alignment.center,
child: IconButton(
icon: Icon(Icons.add),
onPressed: () {
showDialog(
context: context,
builder: (context) => AlertDialog(
title: Text('Add Tab'),
content: TextField(
controller: _newTabController,
decoration: InputDecoration(
hintText: 'Enter tab name',
),
),
actions: [
TextButton(
child: Text('Cancel'),
onPressed: () {
Navigator.pop(context);
},
),
TextButton(
child: Text('Add'),
onPressed: () {
_addTab();
Navigator.pop(context);
},
),
],
),
);
},
),
),
],
),
),
],
),
),
),
SliverToBoxAdapter(
child: SizedBox(
height: size.height - 170,
child: PageView(
controller: _pageController,
onPageChanged: (index) {
if (index == _tabController.length - 1 &&
workoutMap[currentPageIndx]['content'].length <
4) {
_pageController.jumpToPage(_tabController.index);
} else {
_tabController.animateTo(index);
}
},
children: [
...workoutMap[currentPageIndx]['content'].map(
(tab) => Container(
child: tab['exercises'].length == 0
? Column(
mainAxisAlignment:
MainAxisAlignment.center,
children: [
Icon(
Icons.sentiment_very_dissatisfied,
size: size.width * 0.3,
color: Colors.white,
),
SizedBox(height: 10),
Text(
'This folder is empty. Add some workouts',
style: TextStyle(
color: Colors.white),
textAlign: TextAlign.center,
),
SizedBox(height: size.height * .1),
],
)
: Container(
height: size.height, // specify height
child: ReorderableListView.builder(
onReorder:
(int oldIndex, int newIndex) {
setState(() {
if (newIndex > oldIndex) {
newIndex -= 1;
}
final item = tab['exercises']
.removeAt(oldIndex);
tab['exercises']
.insert(newIndex, item);
});
},
itemCount: tab['exercises'].length,
itemBuilder: (BuildContext context,
int index) {
final exercise =
tab['exercises'][index];
return Container(
key: ValueKey(exercise),
margin: EdgeInsets.all(5.0),
decoration: BoxDecoration(
color: Colors.black,
borderRadius:
BorderRadius.circular(
10.0),
),
child: Column(
children: [
Container(
height: size.height * .15,
decoration: BoxDecoration(
color: Color.fromARGB(
255, 45, 45, 45),
borderRadius:
BorderRadius
.circular(10.0),
),
child: Stack(
children: [
Positioned(
top: 10,
left: 10,
child: Container(
width:
size.width *
.4,
child: ClipRRect(
borderRadius:
BorderRadius
.circular(
10.0),
child: Image
.network(
'https://i.giphy.com/media/14kdiJUblbWBXy/giphy.gif', // Replace with your GIF URL
),
),
),
),
Positioned(
top: 10,
left: size.width *
.4 +
20,
child: Column(
crossAxisAlignment:
CrossAxisAlignment
.start,
children: [
Text(
exercise[
'name'],
style: TextStyle(
color: Color.fromARGB(
255,
255,
255,
255),
fontSize:
20,
fontWeight:
FontWeight
.bold),
),
Text(
'Muscles Worked: \n' +
(exercise['musclesworked']
as List)
.join(
', '), // join the list into a string
style: TextStyle(
fontSize:
16,
color: Colors
.white), // adjust style as needed
),
],
),
),
],
),
),
SizedBox(height: 10),
Row(
children: [
Spacer(),
Text(
'3 Sets', // Replace with your sets, reps, and weight data
style: TextStyle(
color: Colors.white,
),
textAlign:
TextAlign.center,
),
Spacer(),
Text(
'4 reps', // Replace with your sets, reps, and weight data
style: TextStyle(
color: Colors.white,
),
textAlign:
TextAlign.center,
),
Spacer(),
Text(
'30 kg', // Replace with your sets, reps, and weight data
style: TextStyle(
color: Colors.white,
),
textAlign:
TextAlign.center,
),
Spacer(),
],
),
SizedBox(height: 10),
],
),
);
},
))),
),
],
),
),
),
],
),
Footer(tab: 'Workout'),
//if (dropdownVisible)
Positioned(
bottom: 60,
left: 0,
right: 0,
child: Column(children: [
Transform.translate(
offset: Offset(0, 0),
child: Center(
child: Container(
width: size.width * 0.8,
child: Row(
children: [
Spacer(),
Container(
width: 30,
height: 30,
child: ElevatedButton(
onPressed: () => {print('clicked')},
style: ElevatedButton.styleFrom(
padding: EdgeInsets.all(0),
shape: RoundedRectangleBorder(
borderRadius:
BorderRadius.circular(1000.0),
),
primary: Color.fromARGB(255, 49, 188, 10),
),
child: Align(
alignment: Alignment.center,
child: Text(
'+',
style: TextStyle(
fontSize: 25, color: Colors.white),
),
),
),
),
],
),
),
),
),
])),
],
),
),
),
),
);
}
}
1条答案
按热度按时间55ooxyrt1#
你需要确保你有所需的“组件”。请继续尝试这个:
ReorderableListView.builder
而不是使用列表中的map。下面是一些例子:
itemBuilder
回调用于构建列表项,其中Container
PackageListTile
,每个项都分配了一个ValueKey
以进行重新排序。除了使用builder,你还应该:
将ReorderableListView移动到CustomScrollView之外,并使用Expanded小部件 Package ReorderableListView,以允许它占用父容器中的剩余可用空间
希望现在能成功