如何为选定的 ListItem onTap 着色
How to color selected ListItem onTap
我想像这样为 ListView 中的 select 值着色:
问题是我尝试打印所有内容,代码:
class _ProcedureList extends State<ProcedureList> {
bool isSelected = true;
_isSelected() {
setState(() {
if (isSelected) {
isSelected = false;
} else {
isSelected = true;
}
});
}
@override
Widget build(BuildContext context) {
var procedureList = widget.filteredkits
.where((kit) => kit.brand == widget.brand)
.map((kit) => kit.procedure)
.toSet()
.toList();
return Expanded(
flex: 2,
child: Container(
padding: EdgeInsets.only(left: 35.0),
child: new ListView.builder(
itemCount: procedureList.length,
itemBuilder: (BuildContext context, int index) {
return Padding(
padding: EdgeInsets.all(6.0),
child: Column(
children: <Widget>[
new Container(
width: 300.0,
height: 30.0,
color: Colors.grey[700],
padding: EdgeInsets.all(6.0),
child: new Text(widget.brand),
),
GestureDetector(
onTap: () => widget.getProcedureSelectedandList(procedureList[index].toString()) & _isSelected(),
child: Container(
width: 300.0,
padding: EdgeInsets.all(3.0),
color: !isSelected ? Colors.white : Colors.orange,
child:
new Text(procedureList[index])
),
),
],
),
);
},
),
),
);
}
}
这就是我的成就,全是彩色的:
我不知道如何在事件发生时只为一项着色,以及我们是否可以更好地更改同一事件的文本颜色。
您需要做的是重构您的代码,以便传递到 ListView
builder
函数的小部件拥有它自己的 StatefulWidget
。因此,将构建器函数内的小部件树移动到它自己单独的 StatefulWidget
中,并在那里处理状态操作逻辑而不是 ProcedureList
。你得到这种行为的原因是因为从 ListView.builder
生成的每个实例都暴露在相同的状态值 isSelected
通过将你的逻辑移动到一个单独的 StatefulWidget
每个实例将有自己的状态。
您应该为列表中的每个项目设置一个 isSelected 值,然后当用户单击列表中的项目之一时,您将更改仅针对录音项目索引和构建中的 isSelected 值声明你应该根据传入索引
的 isSelected 值执行操作
这里是例子:
class MyListWidgetState extends State<MyListWidget> {
List<String> items = ["A", "B", "C", "D", "E", "F"];
Map<int, bool> itemsSelectedValue = Map();
@override
Widget build(BuildContext context) {
return new ListView.builder(
itemCount: items.length,
itemBuilder: (context, index) {
bool isCurrentIndexSelected = itemsSelectedValue[index] == null
? false
: itemsSelectedValue[index];
Container contianer;
if (isCurrentIndexSelected) {
contianer = new Container(
alignment: Alignment.center,
height: 100.0,
color: Colors.blue,
child: new Text(
items[index],
style: new TextStyle(color: Colors.red, fontSize: 18.0),
textAlign: TextAlign.center,
),
);
} else {
contianer = new Container(
alignment: Alignment.center,
height: 100.0,
color: Colors.red,
child: new Text(
items[index],
style: new TextStyle(color: Colors.blue, fontSize: 18.0),
textAlign: TextAlign.center,
),
);
}
return GestureDetector(
onTap: () {
print("${!isCurrentIndexSelected}");
itemsSelectedValue[index] = !isCurrentIndexSelected;
setState(() {
print("OnClick : $index + ${itemsSelectedValue[index]}");
});
},
child: Padding(
padding: const EdgeInsets.all(8.0),
child: contianer,
),
);
});
}
}
或者您可以创建 StateFull 小部件,它为列表中的每个项目保留自己的 isSelected 值,如下例所示:
List<String> items = [
"A",
"B",
"C",
"D",
"E",
"F",
"D",
"J",
"K",
"L",
"M",
"P"
];
class SampleApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Sample App',
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: new Scaffold(
body: new ListView.builder(
itemCount: items.length,
itemBuilder: (context, index) {
return new SelectableWidget(
new SelectableWidgetViewModel(
items[index],
isSelected: false,
),
);
},
)),
);
}
}
class SelectableWidget extends StatefulWidget {
final SelectableWidgetViewModel viewModel;
SelectableWidget(this.viewModel);
@override
State<StatefulWidget> createState() {
return SelectableWidgetState();
}
}
class SelectableWidgetState extends State<SelectableWidget> {
@override
void initState() {
super.initState();
}
@override
Widget build(BuildContext context) {
Container container;
if (widget.viewModel.isSelected) {
container = new Container(
alignment: Alignment.center,
height: 100.0,
color: Colors.blue,
child: new Text(
widget.viewModel.title,
style: new TextStyle(color: Colors.red, fontSize: 18.0),
textAlign: TextAlign.center,
),
);
} else {
container = new Container(
alignment: Alignment.center,
height: 100.0,
color: Colors.red,
child: new Text(
widget.viewModel.title,
style: new TextStyle(color: Colors.blue, fontSize: 18.0),
textAlign: TextAlign.center,
),
);
}
return GestureDetector(
onTap: () {
setState(() {
widget.viewModel.isSelected = !widget.viewModel.isSelected;
});
},
child: Padding(
padding: const EdgeInsets.all(8.0),
child: container,
),
);
}
}
class SelectableWidgetViewModel {
bool isSelected;
String title;
SelectableWidgetViewModel(this.title, {this.isSelected = false});
}
出于性能原因,我认为第二种选择更好
抱歉回复晚了。我有更好的解决方案,我已经更改了您的代码
class _ProcedureList extends State<ProcedureList> {
int isSelected = -1; // changed bool to int and set value to -1 on first time if you don't select anything otherwise set 0 to set first one as selected.
_isSelected(int index) { //pass the selected index to here and set to 'isSelected'
setState(() {
isSelected = index;
});
}
@override
Widget build(BuildContext context) {
var procedureList = widget.filteredkits
.where((kit) => kit.brand == widget.brand)
.map((kit) => kit.procedure)
.toSet()
.toList();
return Expanded(
flex: 2,
child: Container(
padding: EdgeInsets.only(left: 35.0),
child: new ListView.builder(
itemCount: procedureList.length,
itemBuilder: (BuildContext context, int index) {
return Padding(
padding: EdgeInsets.all(6.0),
child: Column(
children: <Widget>[
new Container(
width: 300.0,
height: 30.0,
color: Colors.grey[700],
padding: EdgeInsets.all(6.0),
child: new Text(widget.brand),
),
GestureDetector(
onTap: () => widget.getProcedureSelectedandList(procedureList[index].toString()) & _isSelected(index), //pass index value to '_isSelected'
child: Container(
width: 300.0,
padding: EdgeInsets.all(3.0),
color: isSelected != null && isSelected == index //set condition like this. voila! if isSelected and list index matches it will colored as white else orange.
? Colors.white
: Colors.orange,
child:
new Text(procedureList[index])
),
),
],
),
);
},
),
),
);
}
}
还是一头雾水check this blog
我想像这样为 ListView 中的 select 值着色:
问题是我尝试打印所有内容,代码:
class _ProcedureList extends State<ProcedureList> {
bool isSelected = true;
_isSelected() {
setState(() {
if (isSelected) {
isSelected = false;
} else {
isSelected = true;
}
});
}
@override
Widget build(BuildContext context) {
var procedureList = widget.filteredkits
.where((kit) => kit.brand == widget.brand)
.map((kit) => kit.procedure)
.toSet()
.toList();
return Expanded(
flex: 2,
child: Container(
padding: EdgeInsets.only(left: 35.0),
child: new ListView.builder(
itemCount: procedureList.length,
itemBuilder: (BuildContext context, int index) {
return Padding(
padding: EdgeInsets.all(6.0),
child: Column(
children: <Widget>[
new Container(
width: 300.0,
height: 30.0,
color: Colors.grey[700],
padding: EdgeInsets.all(6.0),
child: new Text(widget.brand),
),
GestureDetector(
onTap: () => widget.getProcedureSelectedandList(procedureList[index].toString()) & _isSelected(),
child: Container(
width: 300.0,
padding: EdgeInsets.all(3.0),
color: !isSelected ? Colors.white : Colors.orange,
child:
new Text(procedureList[index])
),
),
],
),
);
},
),
),
);
}
}
这就是我的成就,全是彩色的:
我不知道如何在事件发生时只为一项着色,以及我们是否可以更好地更改同一事件的文本颜色。
您需要做的是重构您的代码,以便传递到 ListView
builder
函数的小部件拥有它自己的 StatefulWidget
。因此,将构建器函数内的小部件树移动到它自己单独的 StatefulWidget
中,并在那里处理状态操作逻辑而不是 ProcedureList
。你得到这种行为的原因是因为从 ListView.builder
生成的每个实例都暴露在相同的状态值 isSelected
通过将你的逻辑移动到一个单独的 StatefulWidget
每个实例将有自己的状态。
您应该为列表中的每个项目设置一个 isSelected 值,然后当用户单击列表中的项目之一时,您将更改仅针对录音项目索引和构建中的 isSelected 值声明你应该根据传入索引
的 isSelected 值执行操作这里是例子:
class MyListWidgetState extends State<MyListWidget> {
List<String> items = ["A", "B", "C", "D", "E", "F"];
Map<int, bool> itemsSelectedValue = Map();
@override
Widget build(BuildContext context) {
return new ListView.builder(
itemCount: items.length,
itemBuilder: (context, index) {
bool isCurrentIndexSelected = itemsSelectedValue[index] == null
? false
: itemsSelectedValue[index];
Container contianer;
if (isCurrentIndexSelected) {
contianer = new Container(
alignment: Alignment.center,
height: 100.0,
color: Colors.blue,
child: new Text(
items[index],
style: new TextStyle(color: Colors.red, fontSize: 18.0),
textAlign: TextAlign.center,
),
);
} else {
contianer = new Container(
alignment: Alignment.center,
height: 100.0,
color: Colors.red,
child: new Text(
items[index],
style: new TextStyle(color: Colors.blue, fontSize: 18.0),
textAlign: TextAlign.center,
),
);
}
return GestureDetector(
onTap: () {
print("${!isCurrentIndexSelected}");
itemsSelectedValue[index] = !isCurrentIndexSelected;
setState(() {
print("OnClick : $index + ${itemsSelectedValue[index]}");
});
},
child: Padding(
padding: const EdgeInsets.all(8.0),
child: contianer,
),
);
});
}
}
或者您可以创建 StateFull 小部件,它为列表中的每个项目保留自己的 isSelected 值,如下例所示:
List<String> items = [
"A",
"B",
"C",
"D",
"E",
"F",
"D",
"J",
"K",
"L",
"M",
"P"
];
class SampleApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Sample App',
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: new Scaffold(
body: new ListView.builder(
itemCount: items.length,
itemBuilder: (context, index) {
return new SelectableWidget(
new SelectableWidgetViewModel(
items[index],
isSelected: false,
),
);
},
)),
);
}
}
class SelectableWidget extends StatefulWidget {
final SelectableWidgetViewModel viewModel;
SelectableWidget(this.viewModel);
@override
State<StatefulWidget> createState() {
return SelectableWidgetState();
}
}
class SelectableWidgetState extends State<SelectableWidget> {
@override
void initState() {
super.initState();
}
@override
Widget build(BuildContext context) {
Container container;
if (widget.viewModel.isSelected) {
container = new Container(
alignment: Alignment.center,
height: 100.0,
color: Colors.blue,
child: new Text(
widget.viewModel.title,
style: new TextStyle(color: Colors.red, fontSize: 18.0),
textAlign: TextAlign.center,
),
);
} else {
container = new Container(
alignment: Alignment.center,
height: 100.0,
color: Colors.red,
child: new Text(
widget.viewModel.title,
style: new TextStyle(color: Colors.blue, fontSize: 18.0),
textAlign: TextAlign.center,
),
);
}
return GestureDetector(
onTap: () {
setState(() {
widget.viewModel.isSelected = !widget.viewModel.isSelected;
});
},
child: Padding(
padding: const EdgeInsets.all(8.0),
child: container,
),
);
}
}
class SelectableWidgetViewModel {
bool isSelected;
String title;
SelectableWidgetViewModel(this.title, {this.isSelected = false});
}
出于性能原因,我认为第二种选择更好
抱歉回复晚了。我有更好的解决方案,我已经更改了您的代码
class _ProcedureList extends State<ProcedureList> {
int isSelected = -1; // changed bool to int and set value to -1 on first time if you don't select anything otherwise set 0 to set first one as selected.
_isSelected(int index) { //pass the selected index to here and set to 'isSelected'
setState(() {
isSelected = index;
});
}
@override
Widget build(BuildContext context) {
var procedureList = widget.filteredkits
.where((kit) => kit.brand == widget.brand)
.map((kit) => kit.procedure)
.toSet()
.toList();
return Expanded(
flex: 2,
child: Container(
padding: EdgeInsets.only(left: 35.0),
child: new ListView.builder(
itemCount: procedureList.length,
itemBuilder: (BuildContext context, int index) {
return Padding(
padding: EdgeInsets.all(6.0),
child: Column(
children: <Widget>[
new Container(
width: 300.0,
height: 30.0,
color: Colors.grey[700],
padding: EdgeInsets.all(6.0),
child: new Text(widget.brand),
),
GestureDetector(
onTap: () => widget.getProcedureSelectedandList(procedureList[index].toString()) & _isSelected(index), //pass index value to '_isSelected'
child: Container(
width: 300.0,
padding: EdgeInsets.all(3.0),
color: isSelected != null && isSelected == index //set condition like this. voila! if isSelected and list index matches it will colored as white else orange.
? Colors.white
: Colors.orange,
child:
new Text(procedureList[index])
),
),
],
),
);
},
),
),
);
}
}
还是一头雾水check this blog