Flutter - 如何访问 ListView.builder 中的一个元素?
Posted
技术标签:
【中文标题】Flutter - 如何访问 ListView.builder 中的一个元素?【英文标题】:Flutter - How to access one element in ListView.builder? 【发布时间】:2020-05-12 23:51:11 【问题描述】:我有一个列表视图,其中包含从对象列表(报价)创建的元素。每个报价都有关于其自身的详细信息。我想在点击后更改图标 (_isFavIcon
)。但是当我点击它时,它会改变列表的每个元素(每个图标)。
同样在更改图标后,我想将它们添加到另一个列表中。但那是以后的事了。
它的外观如下:ListView
也许我应该使用ListView
而不是ListView.builder
?
这是我的代码:
class OfferList extends StatefulWidget
final List<Offer> offers;
OfferList(this.offers);
@override
_OfferListState createState() => _OfferListState();
class _OfferListState extends State<OfferList>
bool isPressed = true;
Icon _isFavIcon = new Icon(
Icons.favorite_border,
color: Colors.red,
);
@override
Widget build(BuildContext context)
final mediaQuery = MediaQuery.of(context);
_addToFavorites()
_isFavIcon = new Icon(Icons.favorite, color: Colors.red);
return Container(
height: 700,
child: ListView.builder(
itemBuilder: (ctx, index)
return Stack(
children: <Widget>[
Container(
decoration: BoxDecoration(
gradient: LinearGradient(
begin: Alignment.topRight,
end: Alignment.bottomLeft,
colors: [
Colors.white,
Colors.lightBlueAccent.withOpacity(0.2)
])),
width: mediaQuery.size.width,
child: Card(
child: Row(
children: <Widget>[
Container(
margin: EdgeInsets.symmetric(
vertical: 15,
horizontal: 15,
),
child: Container(
decoration: BoxDecoration(
boxShadow: [
BoxShadow(
color: Colors.grey.withOpacity(0.3),
spreadRadius: 1.2,
blurRadius: 7,
),
],
),
child: Image.asset(widget.offers[index].flag),
),
padding: EdgeInsets.all(5),
),
Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
Container(
width: 150,
child: Text(
widget.offers[index].title,
style: TextStyle(
fontSize: 16,
fontWeight: FontWeight.bold,
),
),
),
Text(
'From: ' +
DateFormat.yMMMd()
.format(widget.offers[index].dateFrom),
style: TextStyle(
color: Colors.grey,
),
),
Text(
'To: ' +
DateFormat.yMMMd()
.format(widget.offers[index].dateTo),
style: TextStyle(
color: Colors.grey,
),
),
],
),
Padding(
padding: EdgeInsets.all(8.0),
child: Row(
children: <Widget>[
RaisedButton(
color: Colors.lightBlueAccent,
textColor: Colors.white,
shape: RoundedRectangleBorder(
borderRadius: new BorderRadius.circular(30.0),
),
child: Text('Open'),
onPressed: () ,
),
Container(
padding: EdgeInsets.only(left: 10),
child: InkWell(
onTap: ()
setState(()
_addToFavorites();
);
,
child: _isFavIcon,
),
),
],
),
),
],
),
),
),
],
);
,
itemCount: widget.offers.length,
),
);
【问题讨论】:
将您的ListItem
拆分为自己的 StatefulWidget
。
【参考方案1】:
您可以同时满足这两个要求(切换 favIcon 并拥有收藏列表)添加列表并检查该项目何时在该列表中以显示图标。
class OfferList extends StatefulWidget
final List<Offer> offers;
OfferList(this.offers);
@override
_OfferListState createState() => _OfferListState();
class _OfferListState extends State<OfferList>
bool isPressed = true;
List<Offer> _favOffers = [];
@override
Widget build(BuildContext context)
final mediaQuery = MediaQuery.of(context);
void _toggleFavorite(Offer offer)
if (_favOffers.contains(offer))
_favOffers.remove(offer);
else
_favOffers.add(offer);
return Container(
height: 700,
child: ListView.builder(
itemBuilder: (ctx, index)
return Stack(
children: <Widget>[
Container(
decoration: BoxDecoration(
gradient: LinearGradient(
begin: Alignment.topRight,
end: Alignment.bottomLeft,
colors: [
Colors.white,
Colors.lightBlueAccent.withOpacity(0.2)
])),
width: mediaQuery.size.width,
child: Card(
child: Row(
children: <Widget>[
Container(
margin: EdgeInsets.symmetric(
vertical: 15,
horizontal: 15,
),
child: Container(
decoration: BoxDecoration(
boxShadow: [
BoxShadow(
color: Colors.grey.withOpacity(0.3),
spreadRadius: 1.2,
blurRadius: 7,
),
],
),
child: Image.asset(widget.offers[index].flag),
),
padding: EdgeInsets.all(5),
),
Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
Container(
width: 150,
child: Text(
widget.offers[index].title,
style: TextStyle(
fontSize: 16,
fontWeight: FontWeight.bold,
),
),
),
Text(
'From: ' +
DateFormat.yMMMd()
.format(widget.offers[index].dateFrom),
style: TextStyle(
color: Colors.grey,
),
),
Text(
'To: ' +
DateFormat.yMMMd()
.format(widget.offers[index].dateTo),
style: TextStyle(
color: Colors.grey,
),
),
],
),
Padding(
padding: EdgeInsets.all(8.0),
child: Row(
children: <Widget>[
RaisedButton(
color: Colors.lightBlueAccent,
textColor: Colors.white,
shape: RoundedRectangleBorder(
borderRadius: new BorderRadius.circular(30.0),
),
child: Text('Open'),
onPressed: () ,
),
Container(
padding: EdgeInsets.only(left: 10),
child: InkWell(
onTap: ()
setState(()
_toggleFavorite(widget.offers[index]);
);
,
child:
(_favOffers.contains(widget.offers[index]))
? Icon(
Icons.favorite,
color: Colors.red,
)
: Icon(
Icons.favorite_border,
color: Colors.black,
),
),
),
],
),
),
],
),
),
),
],
);
,
itemCount: widget.offers.length,
),
);
【讨论】:
【参考方案2】:实际上,您正在为所有项目覆盖 _isFavIcon
。
您需要向您的 Offer
模型添加一个名为 isFavorite
的属性,并在 onTap 方法上切换 isFavorite
属性
这是您案例的完整工作示例
报价模式
class Offer
// other attributes
bool isFavorite = false;
优惠列表小部件
class OfferList extends StatefulWidget
final List<Offer> offers;
OfferList(this.offers);
@override
_OfferListState createState() => _OfferListState();
class _OfferListState extends State<OfferList>
bool isPressed = true;
Icon _isNotFavIcon = new Icon(
Icons.favorite_border,
color: Colors.red,
);
Icon _isFavIcon = new Icon(
Icons.favorite,
color: Colors.red,
);
List<Offer> _offers;
@override
void initState()
_offers = widget.offers;
super.initState();
@override
Widget build(BuildContext context)
final mediaQuery = MediaQuery.of(context);
return Container(
height: 700,
child: ListView.builder(
itemBuilder: (ctx, index)
return Stack(
children: <Widget>[
Container(
decoration: BoxDecoration(
gradient: LinearGradient(
begin: Alignment.topRight,
end: Alignment.bottomLeft,
colors: [
Colors.white,
Colors.lightBlueAccent.withOpacity(0.2)
])),
width: mediaQuery.size.width,
child: Card(
child: Row(
children: <Widget>[
Container(
margin: EdgeInsets.symmetric(
vertical: 15,
horizontal: 15,
),
child: Container(
decoration: BoxDecoration(
boxShadow: [
BoxShadow(
color: Colors.grey.withOpacity(0.3),
spreadRadius: 1.2,
blurRadius: 7,
),
],
),
child: Image.asset(_offers[index].flag),
),
padding: EdgeInsets.all(5),
),
Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
Container(
width: 150,
child: Text(
_offers[index].title,
style: TextStyle(
fontSize: 16,
fontWeight: FontWeight.bold,
),
),
),
Text(
'From: ' +
DateFormat.yMMMd()
.format(_offers[index].dateFrom),
style: TextStyle(
color: Colors.grey,
),
),
Text(
'To: ' +
DateFormat.yMMMd()
.format(_offers[index].dateTo),
style: TextStyle(
color: Colors.grey,
),
),
],
),
Padding(
padding: EdgeInsets.all(8.0),
child: Row(
children: <Widget>[
RaisedButton(
color: Colors.lightBlueAccent,
textColor: Colors.white,
shape: RoundedRectangleBorder(
borderRadius: new BorderRadius.circular(30.0),
),
child: Text('Open'),
onPressed: () ,
),
Container(
padding: EdgeInsets.only(left: 10),
child: InkWell(
onTap: ()
setState(()
_offers[index].isFavorite =
!_offers[index].isFavorite;
);
,
child: _offers[index].isFavorite
? _isFavIcon
: _isNotFavIcon,
),
),
],
),
),
],
),
),
),
],
);
,
itemCount: _offers.length,
),
);
【讨论】:
以上是关于Flutter - 如何访问 ListView.builder 中的一个元素?的主要内容,如果未能解决你的问题,请参考以下文章