在 Flutter 中从其子卡重新加载 ListView

Reload ListView from its child card in Flutter

提问人:renji 提问时间:5/21/2020 最后编辑:renji 更新时间:3/3/2023 访问量:910

问:

我开发了一个带有卡片的应用程序。我想在用户点击项目时重新加载/刷新整个项目。LisViewListViewListView

import 'package:flutter/material.dart';

void main() => runApp(MyApp());

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Flutter Demo',
      debugShowCheckedModeBanner: false,
      theme: ThemeData(
        primarySwatch: Colors.blue,
      ),
      home: MyHomePage(title: 'Flutter Demo Home Page'),
    );
  }
}

class MyHomePage extends StatefulWidget {
  MyHomePage({Key key, this.title}) : super(key: key);

  final String title;

  @override
  _MyHomePageState createState() => _MyHomePageState();
}

class _MyHomePageState extends State<MyHomePage> {
  List<String> itemsList = [
    "item0",
    "item1",
    "item2",
    "item3",
    "item4",
    "item5"
  ];

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text(widget.title),
      ),
      body: Center(
          child: ListView.builder(
              itemCount: itemsList.length,
              itemBuilder: (context, index) {
                return ListItemCard(item: itemsList[index]);
              })),
    );
  }
}

class ListItemCard extends StatefulWidget {
  final String item;
  ListItemCard({this.item});
  _ListItemCardState createState() => _ListItemCardState();
}

class _ListItemCardState extends State<ListItemCard> {
  @override
  Widget build(BuildContext context) {
    return Card(
        elevation: 10,
        child: Padding(
            padding: EdgeInsets.all(0.0),
            child: Container(
                child:
              Align(
              alignment: Alignment.centerRight,
              child:Text(
                  widget.item,
                  style: TextStyle(fontSize: 20, fontWeight: FontWeight.bold),
                ),),
                width: 100,
                height: 100,
                color: Colors.red)));
  }
}

我正在使用 Flutter 1.17。我想在用户点击时选择一个项目。我的问题是在选择第二个项目时,应该取消选择已选择的项目。为此,我需要更新整个列表。我的点击事件处理程序在类中_ListItemCardState调用 setState() 只会更新我理解中的特定卡。

ListView Flutter 飞镖

评论

0赞 Ashok Kumar 5/21/2020
如何将 selectedItem 变量保留为类的全局变量,并在卡片项目点击中使用 setState{} 更新它,并在 ternary(?:) 运算符中使用 selectedItem 变量来调节卡片视图中的卡片项目选择状态

答:

0赞 ANUP SAJJAN 5/21/2020 #1

为了解决这个问题,您可以在使用 ListView.builder 时为每张卡指定一个唯一的 ID。 如,

第一张卡的 ID 为 0,

第二张卡的 ID 为 1,

第三张卡的ID为2, .. . 等等。

 body: Center(
      child: ListView.builder(
          itemCount: itemsList.length,
          itemBuilder: (context, index) {
            return ListItemCard(item: itemsList[index],id:index);
          })),
);

现在,当点击一张卡片时,你可以在_MyHomePageState类中有一个回调函数,可以从_ListItemCardState类中调用。并将卡的 id 作为参数传递。

因此,您的主类知道单击了哪张卡片,因此使用 setState 重建 UI,并将布尔值传递给 ListItemCard,说明卡片是否被点击(true)或未单击(false)。

child: ListView.builder(
          itemCount: itemsList.length,
          itemBuilder: (context, index) {
            bool amIclicked = false;
            if (index == clickedCardId) {
              amIclicked = true;
            }
            return ListItemCard(
              item: itemsList[index],
              id: index,
              callbackFunction: this.callbackFunction,
              amIClicked: amIclicked,
            );
          })

和回调函数如下所示:

int clickedCardId = -1;
void callbackFunction(cardId) {
setState(() {
  clickedCardId = cardId;
});

}

整个代码供参考:

import 'package:flutter/material.dart';

void main() => runApp(MyApp());

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Flutter Demo',
      debugShowCheckedModeBanner: false,
      theme: ThemeData(
        primarySwatch: Colors.blue,
      ),
      home: MyHomePage(title: 'Flutter Demo Home Page'),
    );
  }
}

class MyHomePage extends StatefulWidget {
  MyHomePage({Key key, this.title}) : super(key: key);

  final String title;

  @override
  _MyHomePageState createState() => _MyHomePageState();
}

class _MyHomePageState extends State<MyHomePage> {
  List<String> itemsList = [
    "item0",
    "item1",
    "item2",
    "item3",
    "item4",
    "item5"
  ];
  int clickedCardId = -1;
  void callbackFunction(cardId) {
    setState(() {
      clickedCardId = cardId;
    });
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text(widget.title),
      ),
      body: Center(
          child: ListView.builder(
              itemCount: itemsList.length,
              itemBuilder: (context, index) {
                bool amIclicked = false;
                if (index == clickedCardId) {
                  amIclicked = true;
                }
                return ListItemCard(
                  item: itemsList[index],
                  id: index,
                  callbackFunction: this.callbackFunction,
                  amIClicked: amIclicked,
                );
              })),
    );
  }
}

class ListItemCard extends StatefulWidget {
  final String item;
  int id;
  var callbackFunction;
  bool amIClicked;
  ListItemCard(
      {this.item, this.id, this.callbackFunction, this.amIClicked = false});
  _ListItemCardState createState() => _ListItemCardState(
      callbackFunction: callbackFunction, id: id, amIClicked: amIClicked);
}

class _ListItemCardState extends State<ListItemCard> {
  int id;
  var callbackFunction;
  bool amIClicked;
  _ListItemCardState({this.callbackFunction, this.id, this.amIClicked = false});
  //here you finally get "amIClicked" variable with either false or true
  //Based on that , you can show different colors to your card clicked and 
  //-non-clicked
  @override
  Widget build(BuildContext context) {
    return GestureDetector(
      onTap: callbackFunction(id),
      child: Card(
          elevation: 10,
          child: Padding(
              padding: EdgeInsets.all(0.0),
              child: Container(
                  child: Align(
                    alignment: Alignment.centerRight,
                    child: Text(
                      widget.item,
                      style:
                          TextStyle(fontSize: 20, fontWeight: FontWeight.bold),
                    ),
                  ),
                  width: 100,
                  height: 100,
                  color: Colors.red))),
    );
  }
}

希望这有帮助!

评论

0赞 renji 5/21/2020
谢谢。我以为会有一些直接的方法来做到这一点。
0赞 M Owiad 3/3/2023 #2

使用子卡中的提供程序 您的所有更改都将请求父列表重新绘制。如果卡中有任何事情发生变化,列表将通知

评论

0赞 Community 3/8/2023
正如目前所写的那样,你的答案尚不清楚。请编辑以添加其他详细信息,以帮助其他人了解这如何解决所提出的问题。您可以在帮助中心找到有关如何写出好答案的更多信息。