如何在 Flutter 中更新我的 ListView 并解决 StateFull Widget 的问题?
How to update my ListView in Flutter and Solve problem with StateFull Widget?
我的目标是达到Listview的更新。我对我的代码有疑问。但我必须告诉前言我的问题。我使用了 setState(),但我不明白为什么这个函数不起作用,我意识到使用 Stateless 小部件。
I used this code
class _ListItem extends StatelessWidget {
_ListItem({this.bgName, this.name, this.detail});
// final int index;
final String bgName;
final String name;
final String detail;
@override
Widget build(BuildContext context) {
return Container(
height: 180.0,
margin: const EdgeInsets.symmetric(
vertical: 1.0,
),
child: new Stack(
children: <Widget>[
new Container(
decoration: new BoxDecoration(
image: new DecorationImage(
image: new AssetImage(bgName),
colorFilter: new ColorFilter.mode(
Colors.black.withOpacity(0.45), BlendMode.darken),
fit: BoxFit.cover,
alignment: Alignment.center),
),
child: new SizedBox.expand(
child: Container(
alignment: Alignment.center,
child: new Column(
mainAxisAlignment: MainAxisAlignment.center,
crossAxisAlignment: CrossAxisAlignment.center,
mainAxisSize: MainAxisSize.min,
children: <Widget>[
new Text(
name,
style: new TextStyle(fontSize: 29.0, color: Colors.white),
),
Padding(
padding: const EdgeInsets.only(top: 12.0),
child: new Text(
detail,
style:
new TextStyle(fontSize: 16.0, color: Colors.white),
),
)
],
),
),
),
),
],
),
);
}
}
最近,我将 class _ListItem 更改为 Stateful Widget
I used this code
class ListItem extends StatefulWidget {
@override
_ListItem createState() => _ListItem();
}
class _ListItem extends State<ListItem> {
_ListItem({this.bgName, this.name, this.detail});
// final int index;
final String bgName;
final String name;
final String detail;
@override
Widget build(BuildContext context) {
return Container(
height: 180.0,
margin: const EdgeInsets.symmetric(
vertical: 1.0,
),
child: new Stack(
children: <Widget>[
new Container(
decoration: new BoxDecoration(
image: new DecorationImage(
image: new AssetImage(bgName),
colorFilter: new ColorFilter.mode(
Colors.black.withOpacity(0.45), BlendMode.darken),
fit: BoxFit.cover,
alignment: Alignment.center),
),
child: new SizedBox.expand(
child: Container(
alignment: Alignment.center,
child: new Column(
mainAxisAlignment: MainAxisAlignment.center,
crossAxisAlignment: CrossAxisAlignment.center,
mainAxisSize: MainAxisSize.min,
children: <Widget>[
new Text(
name,
style: new TextStyle(fontSize: 29.0, color: Colors.white),
),
Padding(
padding: const EdgeInsets.only(top: 12.0),
child: new Text(
detail,
style:
new TextStyle(fontSize: 16.0, color: Colors.white),
),
)
],
),
),
),
),
],
),
);
}
}
但在外面它给出了空列表视图。
At this moment I used this fragment of code.
body: ListView.builder(
physics: BouncingScrollPhysics(),
itemCount: listItems.length,
itemBuilder: (BuildContext ctxt, int index){
return GestureDetector(
child: listItems[index].widget,
onTap: () {
//some code
}
);
},
)
All code
import 'package:flutter/material.dart';
import 'package:flutter/cupertino.dart';
import 'dart:ui';
import 'package:samuraigym/my_icons_icons.dart' as custicon;
import 'package:samuraigym/program_training_handler.dart';
class MeasurementsScreen extends StatefulWidget {
@override
_MeasurementsScreenState createState() => _MeasurementsScreenState();
}
class _MeasurementsScreenState extends State<MeasurementsScreen> {
List<_ListItem> listItems;
String lastSelectedValue;
var name = ["Рост", "Вес","Грудь","Плечи","Бицепс"];
var nameItem = ["Рост", "Вес","Грудь","Плечи","Бицепс"];
var indication = ["Введите ваш рост", "Введите ваш вес"];
var indicationItem = ["Введите ваш рост", "Введите ваш вес"];
TextEditingController customcintroller;
void navigationPageProgrammTrainingHandler() {
Navigator.of(context).push(MaterialPageRoute(
builder: (BuildContext context) => ProgrammTrainingHandler()),
);
}
@override
void initState() {
super.initState();
initListItems();
}
Future<String> createAlertDialog(BuildContext context, int indexAl) async{
customcintroller = TextEditingController();
if(indexAl < 2){
String returnVal = await showDialog(context: context, builder: (context){
return AlertDialog(
title: Text(name[indexAl]),
content: TextField(
textDirection: TextDirection.ltr,
controller: customcintroller,
style: TextStyle(
color: Colors.lightGreen[400],
fontSize: 18.5),
decoration: InputDecoration(
contentPadding: EdgeInsets.only(bottom: 4.0),
labelText: indication[indexAl],
alignLabelWithHint: false,
),
keyboardType: TextInputType.phone,
textInputAction: TextInputAction.done,
),
actions: <Widget>[
FlatButton(
child: const Text('ОТМЕНА'),
onPressed: () {
Navigator.of(context).pop();
},
),
FlatButton(
child: const Text('ОК'),
onPressed: () {
setState(() {
indicationItem[indexAl] = customcintroller.text.toString();
Navigator.of(context).pop();
});
},
),
],
);
});
} else if (indexAl > 1){
navigationPageProgrammTrainingHandler();
}
}
@override
Widget build(BuildContext context) {
return new Scaffold(
backgroundColor: Color(0xff2b2b2b),
appBar: AppBar(
title: Text(
'Замеры',
style: new TextStyle(
color: Colors.white,
),),
leading: IconButton(
icon:Icon(Icons.arrow_back),
color: Colors.white ,
onPressed:() => Navigator.of(context).pop(),
),
),
body: ListView.builder(
physics: BouncingScrollPhysics(),
itemCount: listItems.length,
itemBuilder: (BuildContext ctxt, int index){
return GestureDetector(
child: listItems[index].widget,
onTap: () {
createAlertDialog(context, index).then((onValue){
indicationItem[index] = onValue.toString();
});
}
);
},
),
);
}
void initListItems() {
listItems = [
new _ListItem(
bgName: 'assets/images/soso_growth.jpg',
name: nameItem[0],
detail: "Нажми, чтобы добавить свой рост"),
new _ListItem(
bgName: 'assets/images/soso_weight.jpg',
name: nameItem[1],
detail: "Нажми, чтобы добавить свой вес"),
new _ListItem(
bgName: 'assets/images/soso_chest.jpg',
name: nameItem[2],
detail: "PRO-версия"),
new _ListItem(
bgName: 'assets/images/soso_shoulder.jpg',
name: nameItem[3],
detail: "PRO-версия"),
new _ListItem(
bgName: 'assets/images/soso_biceps.jpg',
name: nameItem[4],
detail: "PRO-версия")
];
}
}
class ListItem extends StatefulWidget {
@override
_ListItem createState() => _ListItem();
}
class _ListItem extends State<ListItem> {
_ListItem({this.bgName, this.name, this.detail});
// final int index;
final String bgName;
final String name;
final String detail;
@override
Widget build(BuildContext context) {
return Container(
height: 180.0,
margin: const EdgeInsets.symmetric(
vertical: 1.0,
),
child: new Stack(
children: <Widget>[
new Container(
decoration: new BoxDecoration(
image: new DecorationImage(
image: new AssetImage(bgName),
colorFilter: new ColorFilter.mode(
Colors.black.withOpacity(0.45), BlendMode.darken),
fit: BoxFit.cover,
alignment: Alignment.center),
),
child: new SizedBox.expand(
child: Container(
alignment: Alignment.center,
child: new Column(
mainAxisAlignment: MainAxisAlignment.center,
crossAxisAlignment: CrossAxisAlignment.center,
mainAxisSize: MainAxisSize.min,
children: <Widget>[
new Text(
name,
style: new TextStyle(fontSize: 29.0, color: Colors.white),
),
Padding(
padding: const EdgeInsets.only(top: 12.0),
child: new Text(
detail,
style:
new TextStyle(fontSize: 16.0, color: Colors.white),
),
)
],
),
),
),
),
],
),
);
}
}
请帮帮我。有几天我无法解决问题))
如果您想在有状态小部件中发送数据,您必须在有状态 class 本身中执行此操作,而不是在状态
中
class ListItem extends StatefulWidget {
String bgName;
String name;
String detail;
ListItem({Key key, this.bgName, this.name, this.detail}) : super(key: key);
@override
_ListItem createState() => _ListItem();
}
要在 class 状态下访问它,请这样做:
//somecode
decoration: new BoxDecoration(
image: new DecorationImage(
image: new AssetImage(widget.bgName),
//some code
要更改有状态小部件中的状态,例如在您点击小部件时调用 setState 方法,添加手势检测器或 InkWell 以添加点击功能
并在其中调用设置状态。
制作一个 ListItem 列表以在列表视图生成器中使用它,
List<ListItem> items = [ ListItem(bgName: ' the bgName' ,name :'the
name',detail:'details'),
//add another Items here
];
ListView.builder(
itemCount:items.length,
itemBuilder: (context,index)=>items[index];
);
完整示例
class ListItem extends StatefulWidget {
String bgName;
String name;
String detail;
ListItem({Key key, this.bgName, this.name, this.detail}) : super(key: key);
@override
_ListItem createState() => _ListItem();
}
class _ListItem extends State<ListItem> {
@override
Widget build(BuildContext context) {
return GestureDetector(
onTap: () {
print(widget.bgName);
//call setState here;
setState(() {
widget.bgName = 'this item is tapped';
});
},
child: Container(
height: 180.0,
margin: const EdgeInsets.symmetric(
vertical: 1.0,
),
child: new Stack(
children: <Widget>[
new Container(
decoration: new BoxDecoration(
image: new DecorationImage(
image: new AssetImage(widget.bgName),
colorFilter: new ColorFilter.mode(
Colors.black.withOpacity(0.45), BlendMode.darken),
fit: BoxFit.cover,
alignment: Alignment.center),
),
child: new SizedBox.expand(
child: Container(
alignment: Alignment.center,
child: new Column(
mainAxisAlignment: MainAxisAlignment.center,
crossAxisAlignment: CrossAxisAlignment.center,
mainAxisSize: MainAxisSize.min,
children: <Widget>[
new Text(
widget.name,
style:
new TextStyle(fontSize: 29.0, color: Colors.white),
),
Padding(
padding: const EdgeInsets.only(top: 12.0),
child: new Text(
widget.detail,
style: new TextStyle(
fontSize: 16.0, color: Colors.white),
),
)
],
),
),
),
),
],
),
),
);
}
}
List<ListItem> items = [ ListItem(bgName: ' the bgName' ,name :'the
name',detail:'details'),
//add another Items here
];
body: ListView.builder(
physics: BouncingScrollPhysics(),
itemCount: listItems.length,
itemBuilder: (BuildContext ctxt, int index){
return
listItems[index]
;
},
)
希望能帮到你
为我解决问题的方法是将您的小部件(您的构建器 return 的小部件)包装在一个具有唯一密钥的容器中。
在我的例子中,我 return 在构建器中创建了一个无状态小部件,所以这是对我有用的代码。
这是来自我的 listView 构建器的 return 语句
return new Container(child: CouponWidget(coupons[position],true),
key:UniqueKey()
);
我的目标是达到Listview的更新。我对我的代码有疑问。但我必须告诉前言我的问题。我使用了 setState(),但我不明白为什么这个函数不起作用,我意识到使用 Stateless 小部件。
I used this code
class _ListItem extends StatelessWidget {
_ListItem({this.bgName, this.name, this.detail});
// final int index;
final String bgName;
final String name;
final String detail;
@override
Widget build(BuildContext context) {
return Container(
height: 180.0,
margin: const EdgeInsets.symmetric(
vertical: 1.0,
),
child: new Stack(
children: <Widget>[
new Container(
decoration: new BoxDecoration(
image: new DecorationImage(
image: new AssetImage(bgName),
colorFilter: new ColorFilter.mode(
Colors.black.withOpacity(0.45), BlendMode.darken),
fit: BoxFit.cover,
alignment: Alignment.center),
),
child: new SizedBox.expand(
child: Container(
alignment: Alignment.center,
child: new Column(
mainAxisAlignment: MainAxisAlignment.center,
crossAxisAlignment: CrossAxisAlignment.center,
mainAxisSize: MainAxisSize.min,
children: <Widget>[
new Text(
name,
style: new TextStyle(fontSize: 29.0, color: Colors.white),
),
Padding(
padding: const EdgeInsets.only(top: 12.0),
child: new Text(
detail,
style:
new TextStyle(fontSize: 16.0, color: Colors.white),
),
)
],
),
),
),
),
],
),
);
}
}
最近,我将 class _ListItem 更改为 Stateful Widget
I used this code
class ListItem extends StatefulWidget {
@override
_ListItem createState() => _ListItem();
}
class _ListItem extends State<ListItem> {
_ListItem({this.bgName, this.name, this.detail});
// final int index;
final String bgName;
final String name;
final String detail;
@override
Widget build(BuildContext context) {
return Container(
height: 180.0,
margin: const EdgeInsets.symmetric(
vertical: 1.0,
),
child: new Stack(
children: <Widget>[
new Container(
decoration: new BoxDecoration(
image: new DecorationImage(
image: new AssetImage(bgName),
colorFilter: new ColorFilter.mode(
Colors.black.withOpacity(0.45), BlendMode.darken),
fit: BoxFit.cover,
alignment: Alignment.center),
),
child: new SizedBox.expand(
child: Container(
alignment: Alignment.center,
child: new Column(
mainAxisAlignment: MainAxisAlignment.center,
crossAxisAlignment: CrossAxisAlignment.center,
mainAxisSize: MainAxisSize.min,
children: <Widget>[
new Text(
name,
style: new TextStyle(fontSize: 29.0, color: Colors.white),
),
Padding(
padding: const EdgeInsets.only(top: 12.0),
child: new Text(
detail,
style:
new TextStyle(fontSize: 16.0, color: Colors.white),
),
)
],
),
),
),
),
],
),
);
}
}
但在外面它给出了空列表视图。
At this moment I used this fragment of code.
body: ListView.builder(
physics: BouncingScrollPhysics(),
itemCount: listItems.length,
itemBuilder: (BuildContext ctxt, int index){
return GestureDetector(
child: listItems[index].widget,
onTap: () {
//some code
}
);
},
)
All code
import 'package:flutter/material.dart';
import 'package:flutter/cupertino.dart';
import 'dart:ui';
import 'package:samuraigym/my_icons_icons.dart' as custicon;
import 'package:samuraigym/program_training_handler.dart';
class MeasurementsScreen extends StatefulWidget {
@override
_MeasurementsScreenState createState() => _MeasurementsScreenState();
}
class _MeasurementsScreenState extends State<MeasurementsScreen> {
List<_ListItem> listItems;
String lastSelectedValue;
var name = ["Рост", "Вес","Грудь","Плечи","Бицепс"];
var nameItem = ["Рост", "Вес","Грудь","Плечи","Бицепс"];
var indication = ["Введите ваш рост", "Введите ваш вес"];
var indicationItem = ["Введите ваш рост", "Введите ваш вес"];
TextEditingController customcintroller;
void navigationPageProgrammTrainingHandler() {
Navigator.of(context).push(MaterialPageRoute(
builder: (BuildContext context) => ProgrammTrainingHandler()),
);
}
@override
void initState() {
super.initState();
initListItems();
}
Future<String> createAlertDialog(BuildContext context, int indexAl) async{
customcintroller = TextEditingController();
if(indexAl < 2){
String returnVal = await showDialog(context: context, builder: (context){
return AlertDialog(
title: Text(name[indexAl]),
content: TextField(
textDirection: TextDirection.ltr,
controller: customcintroller,
style: TextStyle(
color: Colors.lightGreen[400],
fontSize: 18.5),
decoration: InputDecoration(
contentPadding: EdgeInsets.only(bottom: 4.0),
labelText: indication[indexAl],
alignLabelWithHint: false,
),
keyboardType: TextInputType.phone,
textInputAction: TextInputAction.done,
),
actions: <Widget>[
FlatButton(
child: const Text('ОТМЕНА'),
onPressed: () {
Navigator.of(context).pop();
},
),
FlatButton(
child: const Text('ОК'),
onPressed: () {
setState(() {
indicationItem[indexAl] = customcintroller.text.toString();
Navigator.of(context).pop();
});
},
),
],
);
});
} else if (indexAl > 1){
navigationPageProgrammTrainingHandler();
}
}
@override
Widget build(BuildContext context) {
return new Scaffold(
backgroundColor: Color(0xff2b2b2b),
appBar: AppBar(
title: Text(
'Замеры',
style: new TextStyle(
color: Colors.white,
),),
leading: IconButton(
icon:Icon(Icons.arrow_back),
color: Colors.white ,
onPressed:() => Navigator.of(context).pop(),
),
),
body: ListView.builder(
physics: BouncingScrollPhysics(),
itemCount: listItems.length,
itemBuilder: (BuildContext ctxt, int index){
return GestureDetector(
child: listItems[index].widget,
onTap: () {
createAlertDialog(context, index).then((onValue){
indicationItem[index] = onValue.toString();
});
}
);
},
),
);
}
void initListItems() {
listItems = [
new _ListItem(
bgName: 'assets/images/soso_growth.jpg',
name: nameItem[0],
detail: "Нажми, чтобы добавить свой рост"),
new _ListItem(
bgName: 'assets/images/soso_weight.jpg',
name: nameItem[1],
detail: "Нажми, чтобы добавить свой вес"),
new _ListItem(
bgName: 'assets/images/soso_chest.jpg',
name: nameItem[2],
detail: "PRO-версия"),
new _ListItem(
bgName: 'assets/images/soso_shoulder.jpg',
name: nameItem[3],
detail: "PRO-версия"),
new _ListItem(
bgName: 'assets/images/soso_biceps.jpg',
name: nameItem[4],
detail: "PRO-версия")
];
}
}
class ListItem extends StatefulWidget {
@override
_ListItem createState() => _ListItem();
}
class _ListItem extends State<ListItem> {
_ListItem({this.bgName, this.name, this.detail});
// final int index;
final String bgName;
final String name;
final String detail;
@override
Widget build(BuildContext context) {
return Container(
height: 180.0,
margin: const EdgeInsets.symmetric(
vertical: 1.0,
),
child: new Stack(
children: <Widget>[
new Container(
decoration: new BoxDecoration(
image: new DecorationImage(
image: new AssetImage(bgName),
colorFilter: new ColorFilter.mode(
Colors.black.withOpacity(0.45), BlendMode.darken),
fit: BoxFit.cover,
alignment: Alignment.center),
),
child: new SizedBox.expand(
child: Container(
alignment: Alignment.center,
child: new Column(
mainAxisAlignment: MainAxisAlignment.center,
crossAxisAlignment: CrossAxisAlignment.center,
mainAxisSize: MainAxisSize.min,
children: <Widget>[
new Text(
name,
style: new TextStyle(fontSize: 29.0, color: Colors.white),
),
Padding(
padding: const EdgeInsets.only(top: 12.0),
child: new Text(
detail,
style:
new TextStyle(fontSize: 16.0, color: Colors.white),
),
)
],
),
),
),
),
],
),
);
}
}
请帮帮我。有几天我无法解决问题))
如果您想在有状态小部件中发送数据,您必须在有状态 class 本身中执行此操作,而不是在状态
中 class ListItem extends StatefulWidget {
String bgName;
String name;
String detail;
ListItem({Key key, this.bgName, this.name, this.detail}) : super(key: key);
@override
_ListItem createState() => _ListItem();
}
要在 class 状态下访问它,请这样做:
//somecode
decoration: new BoxDecoration(
image: new DecorationImage(
image: new AssetImage(widget.bgName),
//some code
要更改有状态小部件中的状态,例如在您点击小部件时调用 setState 方法,添加手势检测器或 InkWell 以添加点击功能 并在其中调用设置状态。 制作一个 ListItem 列表以在列表视图生成器中使用它,
List<ListItem> items = [ ListItem(bgName: ' the bgName' ,name :'the
name',detail:'details'),
//add another Items here
];
ListView.builder(
itemCount:items.length,
itemBuilder: (context,index)=>items[index];
);
完整示例
class ListItem extends StatefulWidget {
String bgName;
String name;
String detail;
ListItem({Key key, this.bgName, this.name, this.detail}) : super(key: key);
@override
_ListItem createState() => _ListItem();
}
class _ListItem extends State<ListItem> {
@override
Widget build(BuildContext context) {
return GestureDetector(
onTap: () {
print(widget.bgName);
//call setState here;
setState(() {
widget.bgName = 'this item is tapped';
});
},
child: Container(
height: 180.0,
margin: const EdgeInsets.symmetric(
vertical: 1.0,
),
child: new Stack(
children: <Widget>[
new Container(
decoration: new BoxDecoration(
image: new DecorationImage(
image: new AssetImage(widget.bgName),
colorFilter: new ColorFilter.mode(
Colors.black.withOpacity(0.45), BlendMode.darken),
fit: BoxFit.cover,
alignment: Alignment.center),
),
child: new SizedBox.expand(
child: Container(
alignment: Alignment.center,
child: new Column(
mainAxisAlignment: MainAxisAlignment.center,
crossAxisAlignment: CrossAxisAlignment.center,
mainAxisSize: MainAxisSize.min,
children: <Widget>[
new Text(
widget.name,
style:
new TextStyle(fontSize: 29.0, color: Colors.white),
),
Padding(
padding: const EdgeInsets.only(top: 12.0),
child: new Text(
widget.detail,
style: new TextStyle(
fontSize: 16.0, color: Colors.white),
),
)
],
),
),
),
),
],
),
),
);
}
}
List<ListItem> items = [ ListItem(bgName: ' the bgName' ,name :'the
name',detail:'details'),
//add another Items here
];
body: ListView.builder(
physics: BouncingScrollPhysics(),
itemCount: listItems.length,
itemBuilder: (BuildContext ctxt, int index){
return
listItems[index]
;
},
)
希望能帮到你
为我解决问题的方法是将您的小部件(您的构建器 return 的小部件)包装在一个具有唯一密钥的容器中。
在我的例子中,我 return 在构建器中创建了一个无状态小部件,所以这是对我有用的代码。
这是来自我的 listView 构建器的 return 语句
return new Container(child: CouponWidget(coupons[position],true),
key:UniqueKey()
);