扑朔迷离-刷新和有状态的小部件

时间:2020-07-12 12:34:49

标签: flutter

我被困住了,我认为我完全迷失了Flutter的逻辑。我要执行以下操作:

class HomeScreen extends StatefulWidget {
  static String id = 'home_screen';

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

class _HomeScreenState extends State<HomeScreen> {

@override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
   
        actions: <Widget>[
          IconButton(
            icon: Icon(Icons.refresh),
            onPressed: () {
              ** I WANT TO CALL REFRESH ON THE EVENT LIST**
            },
          ),
        ],
      ),
      body: Column(
        children: <Widget>[
          EventList(),
...

class EventList extends StatefulWidget {
  @override
  _EventListState createState() => _EventListState();
}

class _EventListState extends State<EventList> {
  List<Event> eventList = [];

  @override
  void initState() {
    super.initState();
    getEventList();
  }

  Future<Null> getEventList() async {
   
    // Fill eventList from a web service ...

    setState(() {
  
    });
  }

  @override
  Widget build(BuildContext context) {
    return Expanded(
      child: Container(
         child: (eventList == null || eventList.length == 0)
            ? Center(
                child: CircularProgressIndicator()
            : ListView.builder(
                itemCount: (eventList == null) ? 0 : eventList.length,
                itemBuilder: (BuildContext context, int index) {
...

此逻辑用于在Web服务上使用GET进行首次数据提取。

如何调用refresh()在主屏幕上获取新数据并要求EventList刷新(再次调用getEventList())并重建?

谢谢

3 个答案:

答案 0 :(得分:1)

有很多方法可以解决您的问题。

  1. 第一个是在获取数据后在MainState类中调用setState。这将导致所有子窗口小部件重新生成。但要这样做,您还需要将数据保存在MainState类中,并将其作为参数传递给EventList小部件。 (请注意,您的EventList小部件不再需要是有状态的!因为它不再应该调用setState方法)。

  2. 如果您确实希望将函数包含在EventListState类中,则第二个选择是创建一个在MainState类中实例化的控制器。但这对于像这样简单的任务来说是很多工作。

  3. 第三个是创建一个服务,该服务将是一个单独的类,公开一个Stream,您可以在需要时在其上推送数据。我知道这听起来可能很复杂,所以对于这个例子,这是一个理论示例:

    class MyEventService {
      final StreamController<List<Event>> stateStreamController = StreamController<List<Event>>.broadcast();
    
      Stream<ActionState> get stateStream => stateStreamController.stream;
    
      Future<void> refresh() { fetchFromServer... then stateStreamController.push(data);
    }
    class MainState {
       build(..) => Scaffold(... Button(onPushed: myEventServiceInstance.refresh)
     }
    
    class EventList {
       build(..) => StreamBuilder(stream: myEventServiceInstance.stream...)
    
    }
    
    
    
    

希望这对您有所帮助,不要犹豫,问您是否需要更复杂的样本!

答案 1 :(得分:1)

您可以在下面复制粘贴运行完整代码
工作演示模拟3秒的网络延迟并显示随机数
步骤1:在setState的{​​{1}}中调用IconButton

onPressed

步骤2:在IconButton( icon: Icon(Icons.refresh), onPressed: () { setState(() {}); }, ), 的{​​{1}}中使用didUpdateWidget呼叫_EventListState

addPostFrameCallback

工作演示

enter image description here

单击刷新按钮时的执行顺序

getEventList()

完整代码

@override
  void didUpdateWidget(EventList oldWidget) {
    super.didUpdateWidget(oldWidget);
    WidgetsBinding.instance.addPostFrameCallback((_) {
      getEventList();
    });
  }

答案 2 :(得分:0)

在扑朔迷离中,您不能从父级调用子函数,我建议将它们组合在一个有状态的小部件中,或者将支架放入eventList小部件中,以便将应用程序栏和ListView放在同一statfull小部件中

class HomeScreen extends StatefulWidget {
  static String id = 'home_screen';

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

class _HomeScreenState extends State<HomeScreen> {
  List<Event> eventList = [];

  @override
  void initState() {
    super.initState();
    getEventList();
  }

    Future<Null> getEventList() async {
   
    // Fill eventList from a web service ...

    setState(() {
  
    });
  }

@override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
   
        actions: <Widget>[
          IconButton(
            icon: Icon(Icons.refresh),
            onPressed: () => getEventList(),
          ),
        ],
      ),
      body: Column(
        children: <Widget>[
          buildEventList(),
        ]
      ),);

  }




  Widget buildEventList()(BuildContext context) {
    return Expanded(
      child: Container(
         child: (eventList == null || eventList.length == 0)
            ? Center(
                child: CircularProgressIndicator()
            : ListView.builder(
                itemCount: (eventList == null) ? 0 : eventList.length,
                itemBuilder: (BuildContext context, int index) {
..
                }),
    }

  }