我尝试了可重排序软件包https://pub.dev/packages/reorderables我成功移动了仪表板块,但是当我重新启动应用程序时,我的移动被删除了。
因此,解决方案只能是sharedpref解决方案。但我没有找到如何保存此信息
我试图保存并加载newIndex,但是没有成功,我试图保存并加载List _tiles; 但是sharedpref无法保存列表
这是我的代码示例
List<Widget> _tiles;
void _onReorder(int oldIndex, int newIndex) async {
SharedPreferences prefs = await SharedPreferences.getInstance();
setState(() {
Widget row = _tiles.removeAt(oldIndex);
_tiles.insert(newIndex, row);
//prefs.setListWidget('indexList', _tiles); not working
// prefs.setInt('index', newIndex ); not working
});
}
@override
void initState() {
super.initState();
_tiles = <Widget>[
//my widget1
//my widget2
//my widget3
//my widget4
//my widget5
//my widget6
//my widget7
//my widget8
//my widget9
]
}
@override
Widget build(BuildContext context) {
return Column(
crossAxisAlignment: CrossAxisAlignment.center,
children: <Widget>[
ReorderableWrap(
spacing: 0.0,
runSpacing:0,
maxMainAxisCount: 3,
minMainAxisCount: 3,
padding: const EdgeInsets.all(5),
children:_tiles,
onReorder: _onReorder,
onNoReorder: (int index) {
//this callback is optional
debugPrint('${DateTime.now().toString().substring(5, 22)} reorder cancelled. index:$index');
},
onReorderStarted: (int index) {
//this callback is optional
debugPrint('${DateTime.now().toString().substring(5, 22)} reorder started: index:$index');
}
)
]
);
}
}
编辑:这是小部件1。其他小部件相同
new Container (
width: SizeConfig.safeBlockHorizontal * 32,
height: 160,
child :
new Card(
elevation: 8,
shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(10)),
color: Colors.white,
child:
Ink(
child: InkResponse(
splashFactory: InkRipple.splashFactory,
radius: 100,
onTap: () {
},
child:
Padding(
padding: const EdgeInsets.only(top:10),
child:
new Container(
padding: const EdgeInsets.all(0),
child :
new Column(
mainAxisAlignment: MainAxisAlignment.start,
crossAxisAlignment: CrossAxisAlignment.center,
children: <Widget>[
new Container(
height:25,
child :
new Row(
mainAxisAlignment: MainAxisAlignment.center,
crossAxisAlignment: CrossAxisAlignment.center,
children: <Widget>[
Icon(Icons.keyboard_arrow_right, color: Colors.white, size: 15.0),
Text('Planning',textAlign:TextAlign.center, style: TextStyle(
color: Colors.black,
fontWeight: FontWeight.w500,
fontSize: SizeConfig.safeBlockHorizontal * 4),
),
Icon(Icons.keyboard_arrow_right, color: Colors.grey, size: 15.0),
]
),
),
Padding(
padding: const EdgeInsets.all(5),),
Icon(Icons.event_available, color:Color(0xffff9a7b), size: 70.0),
],
),
))
),
)),
)
这是我的设计
编辑#2
现在,我试图在模型中添加资产,但是我不知道该怎么做
void initState() {
// default models list
models = [
Model(index: 0, new Container (
width:90,
height: 90,
child :new FlareActor("assets/pierre.flr", alignment:Alignment.center, fit:BoxFit.contain, animation:"pierre")
), title: 'Coach'),
Model(index: 1, new Image.asset(
"assets/cup.png",
width: 50,
), title: 'Victories'),
Model(index: 2, icon: Icon(Icons.card_giftcard), title: 'Jeux'),
Model(index: 3, icon: Icon(Icons.wb_sunny), title: 'Sunny'),
Model(index: 4, icon: Icon(Icons.cloud), title: 'Cloud'),
Model(index: 5, icon: Icon(Icons.tv), title: 'TV'),
Model(index: 6, icon: Icon(Icons.place), title: 'Location'),
Model(index: 8, icon: Icon(Icons.music_note), title: 'Music'),
// More customization
Model(
index: 7,
icon: Icon(Icons.event_available, color: Color(0xffff9a7b)),
title: 'Planning'),
];
config();
super.initState();
}
这个解决方案不是一个很好的解决方案,我不喜欢它,但是它可行:D
I really appreciate it if anyone would refer a better one
Maybe for this project, it's good to use DB instead of SharedPreferences
but here I used SharedPreferences
.
The question is how to save the order of some widget(each time on reordering, the order of widget changes and we want to save the order of them, after restarting the app the saved order should be fetched).
SharedPreferences
can also save a list of string, so what I did here was:
In the beginning, there should be a default list, that contains the initial order of widget's of the app.
Because widgets are somehow the same and only some of their info is different, I decided to define a model and work with models, instead of a whole complicated widget, I mean when I want to remove or change indexes I do it for a list of models rather than a list of widgets.
Here I supposed the model only contains a title, I also defined an index for it, so all I do is that when I reorder the widget, it reorders the list of models, to save the order, I save the index of models in any order they are now,
for example, if the initial order was [0, 1, 2, 3] let's say after reordering it's now [3, 0, 1, 2], I save this order, and for the next boot, I fetch the saved order([3, 0, 1, 2]) and then reorder the default list based on this fetched order.
Another solution would be to change the model's index and then show an ordered list of models based on their index.
Here is the code:
import 'package:flutter/material.dart';
import 'package:reorderables/reorderables.dart';
import 'package:shared_preferences/shared_preferences.dart';
void main() => runApp(
MaterialApp(
home: Scaffold(
body: Center(
child: Page(),
),
),
),
);
class Page extends StatefulWidget {
const Page({Key key}) : super(key: key);
@override
_PageState createState() => _PageState();
}
class _PageState extends State<Page> {
SharedPreferences prefs;
List<Model> models;
@override
void initState() {
// default models list
models = [
Model(index: 0, title: 'Item 0'),
Model(index: 1, title: 'Item 1'),
Model(index: 2, title: 'Item 2'),
Model(index: 3, title: 'Item 3'),
];
config();
super.initState();
}
void config() async {
// Here we reset the default model based on saved order
await SharedPreferences.getInstance().then((pref) {
prefs = pref;
List<String> lst = pref.getStringList('indexList');
List<Model> list = [];
if (lst != null && lst.isNotEmpty) {
list = lst
.map(
(String indx) => models
.where((Model item) => int.parse(indx) == item.index)
.first,
)
.toList();
models = list;
}
setState(() {});
});
}
void _onReorder(int oldIndex, int newIndex) async {
Model row = models.removeAt(oldIndex);
models.insert(newIndex, row);
setState(() {
prefs.setStringList(
'indexList', models.map((m) => m.index.toString()).toList());
});
}
@override
Widget build(BuildContext context) {
return ReorderableWrap(
scrollDirection: Axis.vertical,
direction: Axis.vertical,
spacing: 0.0,
runSpacing: 0,
maxMainAxisCount: 3,
minMainAxisCount: 3,
padding: const EdgeInsets.all(5),
children: models
.map((m) => Card(
child: Container(
child: Text('${m.index} - ${m.title}'),
padding: EdgeInsets.all(24.0),
),
))
.toList(),
onReorder: _onReorder,
onNoReorder: (int index) {
//this callback is optional
debugPrint('${DateTime.now().toString().substring(5, 22)} ' +
'reorder cancelled. index:$index');
},
onReorderStarted: (int index) {
//this callback is optional
debugPrint('${DateTime.now().toString().substring(5, 22)} ' +
'reorder started: index:$index');
});
}
}
class Model {
int index;
String title;
Model({this.index, this.title});
@override
String toString() {
return '$index : $title';
}
}
This version is based on the editing to the main question, I decided to keep the first answer unchanged because it's a more simple version and may help another viewer.
For the new model, as far as I could get, it has an icon, title, and an onTap functionality, I changed the model to have icon and title, but for the onTap, I wrote my own card version that gets a model and onTap functionality, I could add onTap to the model, but I thought it's better for future use or to use in other places, so I separated the onTap from the model, I also chose Icon
for the model, it could be IconData
(benefit of IconData
is that you can choose customization for each icon and etc).
On my Card version (MyCard), I simply used a GestureDetector
and Card
to simulate the taps and card.
I wrote a FakePage
that gets a model and if you Tap on each card it navigates to this page and shows some message based on the received model.
要在中清理先前保存的模型SharedPreferences
,您应该注释提取模型顺序的零件,config()
并在下次刷新时,再次取消注释。
这是新版本的代码:
import 'package:flutter/material.dart';
import 'package:reorderables/reorderables.dart';
import 'package:shared_preferences/shared_preferences.dart';
void main() => runApp(
MaterialApp(
home: Scaffold(
body: Center(
child: Page(),
),
),
),
);
class Page extends StatefulWidget {
const Page({Key key}) : super(key: key);
@override
_PageState createState() => _PageState();
}
class _PageState extends State<Page> {
SharedPreferences prefs;
List<Model> models;
@override
void initState() {
// default models list
models = [
Model(index: 0, icon: Icon(Icons.people), title: 'Coach'),
Model(index: 1, icon: Icon(Icons.wb_incandescent), title: 'Victories'),
Model(index: 2, icon: Icon(Icons.card_giftcard), title: 'Jeux'),
Model(index: 3, icon: Icon(Icons.wb_sunny), title: 'Sunny'),
Model(index: 4, icon: Icon(Icons.cloud), title: 'Cloud'),
Model(index: 5, icon: Icon(Icons.tv), title: 'TV'),
Model(index: 6, icon: Icon(Icons.place), title: 'Location'),
Model(index: 8, icon: Icon(Icons.music_note), title: 'Music'),
// More customization
Model(
index: 7,
icon: Icon(Icons.event_available, color: Color(0xffff9a7b)),
title: 'Planning'),
];
config();
super.initState();
}
void config() async {
// Here we reset the default model based on saved order
await SharedPreferences.getInstance().then((pref) {
prefs = pref;
List<String> lst = pref.getStringList('indexList');
List<Model> list = [];
if (lst != null && lst.isNotEmpty) {
list = lst
.map(
(String indx) => models
.where((Model item) => int.parse(indx) == item.index)
.first,
)
.toList();
models = list;
}
setState(() {});
});
}
void _onReorder(int oldIndex, int newIndex) async {
Model row = models.removeAt(oldIndex);
models.insert(newIndex, row);
setState(() {
prefs.setStringList(
'indexList', models.map((m) => m.index.toString()).toList());
});
}
@override
Widget build(BuildContext context) {
return ReorderableWrap(
spacing: 0.0,
runSpacing: 0,
maxMainAxisCount: 3,
minMainAxisCount: 3,
padding: const EdgeInsets.all(5),
children: <Widget>[
MyCard(
model: models[0],
onTap: () => Navigator.of(context).push(
MaterialPageRoute(
builder: (BuildContext context) => FakePage(model: models[0]),
),
),
),
MyCard(
model: models[1],
onTap: () => Navigator.of(context).push(
MaterialPageRoute(
builder: (BuildContext context) => FakePage(model: models[1]),
),
),
),
MyCard(
model: models[2],
onTap: () => Navigator.of(context).push(
MaterialPageRoute(
builder: (BuildContext context) => FakePage(model: models[2]),
),
),
),
MyCard(
model: models[3],
onTap: () => Navigator.of(context).push(
MaterialPageRoute(
builder: (BuildContext context) => FakePage(model: models[3]),
),
),
),
MyCard(
model: models[4],
onTap: () => Navigator.of(context).push(
MaterialPageRoute(
builder: (BuildContext context) => FakePage(model: models[4]),
),
),
),
MyCard(
model: models[5],
onTap: () => Navigator.of(context).push(
MaterialPageRoute(
builder: (BuildContext context) => FakePage(model: models[5]),
),
),
),
MyCard(
model: models[6],
onTap: () => Navigator.of(context).push(
MaterialPageRoute(
builder: (BuildContext context) => FakePage(model: models[6]),
),
),
),
MyCard(
model: models[7],
onTap: () => Navigator.of(context).push(
MaterialPageRoute(
builder: (BuildContext context) => FakePage(model: models[7]),
),
),
),
MyCard(
model: models[8],
onTap: () => Navigator.of(context).push(
MaterialPageRoute(
builder: (BuildContext context) => FakePage(model: models[8]),
),
),
),
],
onReorder: _onReorder,
onNoReorder: (int index) {
//this callback is optional
debugPrint('${DateTime.now().toString().substring(5, 22)} ' +
'reorder cancelled. index:$index');
},
onReorderStarted: (int index) {
//this callback is optional
debugPrint('${DateTime.now().toString().substring(5, 22)} ' +
'reorder started: index:$index');
});
}
}
// ---------------------- Model --------------------------
class Model {
int index;
String title;
Icon icon;
Model({this.index, this.title, this.icon});
@override
String toString() {
return '$index : $title';
}
}
// ------------------------ MyCard ----------------------------
class MyCard extends StatelessWidget {
final Model model;
final void Function() onTap;
const MyCard({Key key, this.onTap, @required this.model})
: assert(model != null),
super(key: key);
@override
Widget build(BuildContext context) {
double width = MediaQuery.of(context).size.width;
return GestureDetector(
onTap: onTap,
child: Card(
elevation: 8.0,
shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(10)),
child: _child(width),
),
);
}
Widget _child(double width) {
return Container(
width: width / 4,
height: width / 3,
margin: EdgeInsets.all(5.0),
child: Column(
mainAxisSize: MainAxisSize.max,
crossAxisAlignment: CrossAxisAlignment.stretch,
children: <Widget>[
Expanded(
flex: 3,
child: Row(
mainAxisSize: MainAxisSize.max,
mainAxisAlignment: MainAxisAlignment.center,
crossAxisAlignment: CrossAxisAlignment.center,
children: <Widget>[
Text(
model.title,
maxLines: 1,
textAlign: TextAlign.center,
style: TextStyle(
color: Colors.black,
fontWeight: FontWeight.w500,
fontSize: 15.0,
),
overflow: TextOverflow.ellipsis,
),
Icon(
Icons.arrow_forward_ios,
color: Colors.grey.shade400,
size: 15.0,
),
],
),
),
Expanded(
flex: 5,
child: Padding(
padding: EdgeInsets.all(8.0),
child: FittedBox(
fit: BoxFit.contain,
child: model.icon,
),
),
),
],
),
);
}
}
// ----------------------- FAKE PAGE ---------------------------
class FakePage extends StatelessWidget {
final Model model;
const FakePage({Key key, this.model}) : super(key: key);
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
backgroundColor: Colors.deepOrangeAccent,
),
body: Center(
child: Column(
mainAxisSize: MainAxisSize.max,
mainAxisAlignment: MainAxisAlignment.center,
crossAxisAlignment: CrossAxisAlignment.center,
children: <Widget>[
Text(
'You Clicked on Card : ${model.title}',
style: TextStyle(fontSize: 20.0),
),
Padding(
padding: EdgeInsets.only(top: 24.0),
child: Icon(
model.icon.icon,
size: 70.0,
),
),
],
),
),
);
}
}
本文收集自互联网,转载请注明来源。
如有侵权,请联系[email protected] 删除。
我来说两句