如何从无状态小部件更改为有状态小部件? [英] How to change from Stateless Widget to Stateful Widget?
问题描述
我有一个使用复选框和下拉菜单的应用程序屏幕。但是,我已经意识到我已经在StatelessWidget中对其进行了编码,因此当选择一个选项时,我无法更改状态。如何使它正常工作,以便在选中一个复选框时它会显示为已选中而不是空?
我尝试将代码粘贴到有状态的小部件,但是会一直出错,因为我不确定哪部分应该放在哪里。
import‘package:carve_brace_app / model / activity.dart’;
导入的 package:flutter / material.dart;
类DetailPage扩展了StatelessWidget {
final Activity活动;
DetailPage({Key key,this.activity}):super(key:key);
@override
小部件构建(BuildContext上下文){
final levelIndicator = Container(
child:Container(
child:LinearProgressIndicator(
backgroundColor:Color.fromRGBO(209,224,224,0.2),
值:2.0,
值Color:AlwaysStoppedAnimation(Colors.green)),
),
);
final topContentText = Column(
crossAxisAlignment:CrossAxisAlignment.start,
子级:< Widget> [
SizedBox(高度:120.0),
容器(
宽度:90.0,
子级:new Divider(color:Colors.green),
),
SizedBox(高度:10.0),
Text(
activity.activityName,
样式:TextStyle(颜色:Colors.white,fontSize:45.0),
),
SizedBox(高度:30.0),
Row($ b) $ b mainAxisAlignment:MainAxisAlignment.start,
子级:< Widget> [
Expanded(
flex:6,
子级:Padding(
padding:EdgeInsets.only (左:10.0),
子级:文本(
上次运行:3-2-19\n +
上次平均应变:34%\n +
上次运行时间:00:45:23,
样式:TextStyle(颜色:Colors.white),
))),
//展开后(flex:1,孩子:newRow)
],
),
],
);
final topContent = Stack(
子级:< Widget> [
容器(
高度:MediaQuery.of(context).size.height * 0.45,
填充:EdgeInsets.all(40.0),
宽度:MediaQuery.of(context).size.width,
装饰:BoxDecoration(
渐变:LinearGradient(
开始:Alignment.centerLeft,
结束:Alignment.centerRight,
颜色:[
Color.fromRGBO(33,147,176,100),
Color.fromRGBO(109,213 ,237,100)
],
),
),
子级:Center(
子级:topContentText,
),
) ,
位置(
左:235.0,
上:180.0,
子级:InkWell(
onTap:(){
Navigator.pop(context) ;
},
chil d:new CircleAvatar(
半径:80.0,
backgroundImage:NetworkImage(activity.icon),
backgroundColor:Colors.white,
),
),
),
位置(
剩余:8.0,
顶部:60.0,
子级:InkWell(
onTap:(){
Navigator.pop (上下文);
},
子级:Icon(Icons.arrow_back,颜色:Colors.white),
),
)
],
);
final bottomContentText = Text(
Config:,
样式:TextStyle(fontSize:18.0),
);
final mappingCheckBox = CheckboxListTile(
标题:Text( Mapped),
值:false,
onChanged:(newValue){},
controlAffinity:ListTileControlAffinity。领先,//<-领先的复选框
);
final rtCheckBox = CheckboxListTile(
title:Text( Real-time Tracking),
value:false,
onChanged:(newValue){},
controlAffinity :ListTileControlAffinity.leading,//<-前导复选框
);
final descriptionText = Text(
Description:,
样式:TextStyle(fontSize:12.0),
);
最终描述= TextFormField(
装饰:InputDecoration(
hintText:‘输入活动描述’,
),
);
final scheduleFor = Text(
Scheduled for:,
样式:TextStyle(fontSize:12.0),
);
最终下拉列表=新的DropdownButton< String>(
项目:< String> ['Now(Default)','B','C','D']。map((String value) {
return new DropdownMenuItem< String>(
value:value,
child:new Text(value),
);
})。toList(),
提示:Text( Now(Default)),
onChanged:(_){},
);
final readButton = Container(
填充:EdgeInsets.symmetric(垂直:16.0),
宽度:170,// MediaQuery.of(context).size.width,
子级:RaisedButton(
onPressed:()=> {},
颜色:Colors.lightBlue,
子级:
Text( Start,样式:TextStyle(color:Colors .white,fontSize:20)),
));
final bottomContent =容器(
宽度:MediaQuery.of(context).size.width,
填充:EdgeInsets.all(40.0),
子级:Center(
子级:列(
子级:< Widget> [bottomContentText,mappedCheckbox,rtCheckBox,descriptionText,description,Text( \n),cheduleFor,下拉菜单,readButton],
),
),
);
return脚手架(
正文:列(
子代:< Widget> [topContent,bottomContent],
),
);
}
}
点击在 StatelessWidget
类上,并使用 option +输入
(或 cmd +。
(如果在macOS上使用VS Code),则会看到一个IDE选项可以帮助您完成此操作。
这是工作代码。
类DetailPage扩展了StatefulWidget {
final Activity活动;
DetailPage({Key key,this.activity}):super(key:key);
@override
_DetailPageState createState()=> _DetailPageState();
}
类_DetailPageState扩展了State< DetailPage> {
bool _tracking = false,_mapped = false; //您需要这个
String _schedule;
@override
小部件build(BuildContext context){
final levelIndicator = Container(
child:Container(
child:LinearProgressIndicator(backgroundColor:Color。 fromRGBO(209,224,224,0.2),值:2.0,valueColor:AlwaysStoppedAnimation(Colors.green)),
),
);
final topContentText = Column(
crossAxisAlignment:CrossAxisAlignment.start,
子级:< Widget> [
SizedBox(高度:120.0),
容器(
宽度:90.0,
子级:Divider(color:Colors.green),
),
SizedBox(高度:10.0),
Text(
widget.activity.activityName,
样式:TextStyle(颜色:Colors.white,fontSize:45.0),
),
SizedBox(高度:30.0),
Row(
mainAxisAlignment:MainAxisAlignment.start,
子级:< Widget> [
Expanded(
flex:6,
子级:Padding(
padding:EdgeInsets)。仅(左:10.0),
子级:文本(
上次运行:3-2-19\n +上次平均应变:34%\n +上次运行时间: 00:45:23,
样式:TextStyle(颜色:Colors.w hite),
))))
//展开后(flex:1,child:newRow)
],
),
],
) ;
final topContent = Stack(
子级:< Widget> [
容器(
高度:MediaQuery.of(context).size.height * 0.45,
填充:EdgeInsets.all(40.0),
宽度:MediaQuery.of(context).size.width,
装饰:BoxDecoration(
渐变:LinearGradient(
开始:Alignment.centerLeft,
结束:Alignment.centerRight,
颜色:[Color.fromRGBO(33,147,176,100),Color.fromRGBO(109,213,237,100)],
),
),
子级:Center(
子级:topContentText,
),
),
位置(剩余
:235.0,
顶部:180.0,
子级:InkWell(
onTap:(){
Navigator.pop(context);
},
子级:CircleAvatar(
半径:80.0,
backgroundColo r:Colors.white,
),
),
),
定位(
左:8.0,
上:60.0,
孩子:InkWell(
onTap:(){
Navigator.pop(context);
},
子级:Icon(Icons.arrow_back,颜色:Colors.white),
),
)
],
);
final bottomContentText = Text(
Config:,
样式:TextStyle(fontSize:18.0),
);
finalappedCheckCheckBox = CheckboxListTile(
title:Text( Mapped),
value:_mapped,
onChanged:(newValue)=> setState(()=> _mapped = newValue),
controlAffinity:ListTileControlAffinity.leading,//<-前导复选框
);
最终rtCheckBox = CheckboxListTile(
标题:Text(实时跟踪),
值:_tracking,
onChanged:(newValue)=> setState(()= > _tracking = newValue),
controlAffinity:ListTileControlAffinity.leading,//<-前导复选框
);
final descriptionText = Text(
Description:,
样式:TextStyle(fontSize:12.0),
);
最终描述= TextFormField(
装饰:InputDecoration(
hintText:‘输入活动描述’,
),
);
final scheduleFor = Text(
Scheduled for:,
样式:TextStyle(fontSize:12.0),
);
最终下拉列表= DropdownButton< String>(
值:_schedule,
项:< String> ['Now(默认)','B','C','D'] .map((String value){
return DropdownMenuItem< String>(
value:value,
child:Text(value),
);
})。 toList(),
提示:Text( Now(Default)),
onChanged:(newValue){
setState((){
_schedule = newValue;
});
},
);
final readButton = Container(
padding:EdgeInsets.symmetric(vertical:16.0),
width:170,//MediaQuery.of(context).size.width,
子级:RaisedButton(
onPressed:()=> {},
颜色:Colors.lightBlue,
子级:Text(开始,样式:TextStyle(颜色:Colors.white,fontSize :20)),
));
final bottomContent =容器(
宽度:MediaQuery.of(context).size.width,
填充:EdgeInsets.all(40.0),
子级:Center(
子级:列(
子级:< Widget> [bottomContentText,mappedCheckbox,rtCheckBox,descriptionText,description,Text( \n),cheduledFor,下拉菜单,readButton],
),
),
);
return脚手架(
正文:列(
子代:< Widget> [topContent,bottomContent],
),
);
}
}
I have an app screen that uses Checkboxes and a Drop down Menu. However, I have realised I'd coded it inside a StatelessWidget so I am unable to change the state when an option is selected. How do I get this working so that when a Checkbox is selected then it will display as being "checked" rather than empty?
I have tried pasting in my code into a Stateful Widget, however keep running into errors, as I am not totally sure on which parts should go where.
import 'package:carve_brace_app/model/activity.dart';
import 'package:flutter/material.dart';
class DetailPage extends StatelessWidget {
final Activity activity;
DetailPage({Key key, this.activity}) : super(key: key);
@override
Widget build(BuildContext context) {
final levelIndicator = Container(
child: Container(
child: LinearProgressIndicator(
backgroundColor: Color.fromRGBO(209, 224, 224, 0.2),
value: 2.0,
valueColor: AlwaysStoppedAnimation(Colors.green)),
),
);
final topContentText = Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
SizedBox(height: 120.0),
Container(
width: 90.0,
child: new Divider(color: Colors.green),
),
SizedBox(height: 10.0),
Text(
activity.activityName,
style: TextStyle(color: Colors.white, fontSize: 45.0),
),
SizedBox(height: 30.0),
Row(
mainAxisAlignment: MainAxisAlignment.start,
children: <Widget>[
Expanded(
flex: 6,
child: Padding(
padding: EdgeInsets.only(left: 10.0),
child: Text(
"Last Run: 3-2-19\n"+
"Last Avg Strain: 34%\n"+
"Last Run Time: 00:45:23",
style: TextStyle(color: Colors.white),
))),
// Expanded(flex: 1, child: newRow)
],
),
],
);
final topContent = Stack(
children: <Widget>[
Container(
height: MediaQuery.of(context).size.height * 0.45,
padding: EdgeInsets.all(40.0),
width: MediaQuery.of(context).size.width,
decoration: BoxDecoration(
gradient: LinearGradient(
begin: Alignment.centerLeft,
end: Alignment.centerRight,
colors: [
Color.fromRGBO(33, 147, 176, 100),
Color.fromRGBO(109, 213, 237, 100)
],
),
),
child: Center(
child: topContentText,
),
),
Positioned(
left: 235.0,
top: 180.0,
child: InkWell(
onTap: () {
Navigator.pop(context);
},
child: new CircleAvatar(
radius: 80.0,
backgroundImage: NetworkImage(activity.icon),
backgroundColor: Colors.white,
),
),
),
Positioned(
left: 8.0,
top: 60.0,
child: InkWell(
onTap: () {
Navigator.pop(context);
},
child: Icon(Icons.arrow_back, color: Colors.white),
),
)
],
);
final bottomContentText = Text(
"Config:",
style: TextStyle(fontSize: 18.0),
);
final mappedCheckbox = CheckboxListTile(
title: Text("Mapped"),
value: false,
onChanged: (newValue) { },
controlAffinity: ListTileControlAffinity.leading, // <-- leading Checkbox
);
final rtCheckBox = CheckboxListTile(
title: Text("Real-time Tracking"),
value: false,
onChanged: (newValue) { },
controlAffinity: ListTileControlAffinity.leading, // <-- leading Checkbox
);
final descriptionText = Text(
"Description:",
style: TextStyle(fontSize: 12.0),
);
final description = TextFormField(
decoration: InputDecoration(
hintText: 'Enter an activity description',
),
);
final scheduledFor = Text(
"Scheduled for:",
style: TextStyle(fontSize: 12.0),
);
final dropdown = new DropdownButton<String>(
items: <String>['Now (Default)', 'B', 'C', 'D'].map((String value) {
return new DropdownMenuItem<String>(
value: value,
child: new Text(value),
);
}).toList(),
hint: Text("Now (Default)"),
onChanged: (_) {},
);
final readButton = Container(
padding: EdgeInsets.symmetric(vertical: 16.0),
width: 170,//MediaQuery.of(context).size.width,
child: RaisedButton(
onPressed: () => {},
color: Colors.lightBlue,
child:
Text("Start", style: TextStyle(color: Colors.white, fontSize: 20)),
));
final bottomContent = Container(
width: MediaQuery.of(context).size.width,
padding: EdgeInsets.all(40.0),
child: Center(
child: Column(
children: <Widget>[bottomContentText, mappedCheckbox, rtCheckBox, descriptionText, description, Text("\n"), scheduledFor, dropdown, readButton],
),
),
);
return Scaffold(
body: Column(
children: <Widget>[topContent, bottomContent],
),
);
}
}
Click on the StatelessWidget
class and use option + enter
(or cmd + .
if you use VS Code on macOS), you will see an IDE option that will help you do that.
Output (Your solution):
Here is the working code.
class DetailPage extends StatefulWidget {
final Activity activity;
DetailPage({Key key, this.activity}) : super(key: key);
@override
_DetailPageState createState() => _DetailPageState();
}
class _DetailPageState extends State<DetailPage> {
bool _tracking = false, _mapped = false; // you need this
String _schedule;
@override
Widget build(BuildContext context) {
final levelIndicator = Container(
child: Container(
child: LinearProgressIndicator(backgroundColor: Color.fromRGBO(209, 224, 224, 0.2), value: 2.0, valueColor: AlwaysStoppedAnimation(Colors.green)),
),
);
final topContentText = Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
SizedBox(height: 120.0),
Container(
width: 90.0,
child: Divider(color: Colors.green),
),
SizedBox(height: 10.0),
Text(
widget.activity.activityName,
style: TextStyle(color: Colors.white, fontSize: 45.0),
),
SizedBox(height: 30.0),
Row(
mainAxisAlignment: MainAxisAlignment.start,
children: <Widget>[
Expanded(
flex: 6,
child: Padding(
padding: EdgeInsets.only(left: 10.0),
child: Text(
"Last Run: 3-2-19\n" + "Last Avg Strain: 34%\n" + "Last Run Time: 00:45:23",
style: TextStyle(color: Colors.white),
))),
// Expanded(flex: 1, child: newRow)
],
),
],
);
final topContent = Stack(
children: <Widget>[
Container(
height: MediaQuery.of(context).size.height * 0.45,
padding: EdgeInsets.all(40.0),
width: MediaQuery.of(context).size.width,
decoration: BoxDecoration(
gradient: LinearGradient(
begin: Alignment.centerLeft,
end: Alignment.centerRight,
colors: [Color.fromRGBO(33, 147, 176, 100), Color.fromRGBO(109, 213, 237, 100)],
),
),
child: Center(
child: topContentText,
),
),
Positioned(
left: 235.0,
top: 180.0,
child: InkWell(
onTap: () {
Navigator.pop(context);
},
child: CircleAvatar(
radius: 80.0,
backgroundColor: Colors.white,
),
),
),
Positioned(
left: 8.0,
top: 60.0,
child: InkWell(
onTap: () {
Navigator.pop(context);
},
child: Icon(Icons.arrow_back, color: Colors.white),
),
)
],
);
final bottomContentText = Text(
"Config:",
style: TextStyle(fontSize: 18.0),
);
final mappedCheckbox = CheckboxListTile(
title: Text("Mapped"),
value: _mapped,
onChanged: (newValue) => setState(() => _mapped = newValue),
controlAffinity: ListTileControlAffinity.leading, // <-- leading Checkbox
);
final rtCheckBox = CheckboxListTile(
title: Text("Real-time Tracking"),
value: _tracking,
onChanged: (newValue) => setState(() => _tracking = newValue),
controlAffinity: ListTileControlAffinity.leading, // <-- leading Checkbox
);
final descriptionText = Text(
"Description:",
style: TextStyle(fontSize: 12.0),
);
final description = TextFormField(
decoration: InputDecoration(
hintText: 'Enter an activity description',
),
);
final scheduledFor = Text(
"Scheduled for:",
style: TextStyle(fontSize: 12.0),
);
final dropdown = DropdownButton<String>(
value: _schedule,
items: <String>['Now (Default)', 'B', 'C', 'D'].map((String value) {
return DropdownMenuItem<String>(
value: value,
child: Text(value),
);
}).toList(),
hint: Text("Now (Default)"),
onChanged: (newValue) {
setState(() {
_schedule = newValue;
});
},
);
final readButton = Container(
padding: EdgeInsets.symmetric(vertical: 16.0),
width: 170, //MediaQuery.of(context).size.width,
child: RaisedButton(
onPressed: () => {},
color: Colors.lightBlue,
child: Text("Start", style: TextStyle(color: Colors.white, fontSize: 20)),
));
final bottomContent = Container(
width: MediaQuery.of(context).size.width,
padding: EdgeInsets.all(40.0),
child: Center(
child: Column(
children: <Widget>[bottomContentText, mappedCheckbox, rtCheckBox, descriptionText, description, Text("\n"), scheduledFor, dropdown, readButton],
),
),
);
return Scaffold(
body: Column(
children: <Widget>[topContent, bottomContent],
),
);
}
}
这篇关于如何从无状态小部件更改为有状态小部件?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!