簡體   English   中英

如何為 futurebuilder 調用 setState

[英]How to call setState for a futurebuilder

我想在使用 FutureBuilder 構建的列表視圖底部隱藏浮動操作按鈕,我在列表視圖中使用了 ScrollerController 來檢測用戶何時向前滾動並隱藏操作按鈕如果用戶向前滾動然后調用 setState 但每當我調用它 FutureBuilder 未來將運行重復這是一個異步 sqlite get 查詢。 我使用了 AsynMemoizer 但這也沒有幫助。 這是我的代碼示例:

class _MyHomePageState extends State<MyHomePage> {
  bool show = true;
  ScrollController _controller = ScrollController();
  final AsyncMemoizer _memoizer = AsyncMemoizer();

  @override
  void initState() {
    super.initState();
    _controller.addListener(listener);
  }

  void listener() {
    if (_controller.position.userScrollDirection == ScrollDirection.forward) {
      show = true;
    } else if (_controller.position.userScrollDirection ==
        ScrollDirection.reverse) {
      show = false;
    }
    setState(() {});
  }

  int _counter = 0;
  int id = 0;
  Future<List<Dog>> _getDogs() async {
    // return this._memoizer.(() async {
    //   return await getDogs();
    // });
  }

  void _insertDog() async {
    id++;
    var fido = Dog(id: id, name: "fido$id", age: id * 3);
    await insertDog(fido);
    setState(() {});
  }

  void _updateDog(Dog fido) async {
    fido = Dog(
      id: fido.id,
      name: fido.name,
      age: fido.age + 7,
    );
    await updateDog(fido);
    setState(() {});
  }

  void _deleteDog(int id) async {
    await deleteDog(id);
    setState(() {});
  }

  @override
  void dispose() {
    _controller.removeListener(listener);
    super.dispose();
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
        appBar: AppBar(
          title: Text("Sqflite Demo"),
        ),
        body: Container(
          child: FutureBuilder(
            future: getDogs(),
            builder: (BuildContext context, AsyncSnapshot snapshot) {
              if (snapshot.connectionState == ConnectionState.done) {
                return ListView.builder(
                  controller: _controller,
                  itemCount: snapshot.data.length,
                  itemBuilder: (BuildContext context, int index) {
                    return ListTile(
                      title: Text(snapshot.data[index].name),
                      subtitle: Text("Age: ${snapshot.data[index].age}"),
                      onTap: () => _updateDog(snapshot.data[index]),
                      onLongPress: () => _deleteDog(snapshot.data[index].id),
                    );
                  },
                );
              } else {
                return Container(
                    child: Center(
                  child: Text("Loading..."),
                ));
              }
            },
          ),
        ),
        floatingActionButton: Visibility(
          visible: show,
          child: Stack(
            children: <Widget>[
              Padding(
                padding: EdgeInsets.only(left: 30),
                child: Align(
                  alignment: Alignment.bottomLeft,
                  child: FloatingActionButton(
                    onPressed: () {
                      setState(() {});
                    },
                    child: Icon(Icons.refresh),
                  ),
                ),
              ),
              Align(
                alignment: Alignment.bottomRight,
                child: FloatingActionButton(
                  onPressed: _insertDog,
                  tooltip: 'Increment',
                  child: Icon(Icons.add),
                ),
              ),
            ],
          ),
        ));
  }
}

在 initState 中調用getDogs() ,將 Future 實例保存在 State 中。 然后在 FutureBuilder 中使用該 Future 變量。 這樣,如果它已經被解決,它就不會在每個build被調用。

與額外信息相關: https : //stackoverflow.com/a/52249579/5617722

感謝 Martyns 提供快速而智能的解決方案,有一點是,每當我想更新列表視圖時,我都必須將 getDogs() 重新分配給未來狀態實例變量以強制 FutureBuilder 運行。 這是正確的源代碼:

class _MyHomePageState extends State<MyHomePage> {
  bool show = true;
  ScrollController _controller = ScrollController();
  Future<List<Dog>> future;
  @override
  void initState() {
    super.initState();
    future = getDogs();
    _controller.addListener(listener);
  }

  void listener() {
    if (_controller.position.userScrollDirection == ScrollDirection.forward) {
      show = true;
    } else if (_controller.position.userScrollDirection ==
        ScrollDirection.reverse) {
      show = false;
    }
    setState(() {});
  }

  int _counter = 0;
  int id = 0;
  void _insertDog() async {
    id++;
    var fido = Dog(id: id, name: "fido$id", age: id * 3);
    await insertDog(fido);
    setState(() {future = getDogs();});
  }

  void _updateDog(Dog fido) async {
    fido = Dog(
      id: fido.id,
      name: fido.name,
      age: fido.age + 7,
    );
    await updateDog(fido);
    setState(() {future = getDogs();});
  }

  void _deleteDog(int id) async {
    await deleteDog(id);
    setState(() {future = getDogs();});
  }

  @override
  void dispose() {
    _controller.removeListener(listener);
    super.dispose();
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
        appBar: AppBar(
          title: Text("Sqflite Demo"),
        ),
        body: Container(
          child: FutureBuilder(
            future: future,
            builder: (BuildContext context, AsyncSnapshot snapshot) {
              if (snapshot.connectionState == ConnectionState.done) {
                return ListView.builder(
                  controller: _controller,
                  itemCount: snapshot.data.length,
                  itemBuilder: (BuildContext context, int index) {
                    return ListTile(
                      title: Text(snapshot.data[index].name),
                      subtitle: Text("Age: ${snapshot.data[index].age}"),
                      onTap: () => _updateDog(snapshot.data[index]),
                      onLongPress: () => _deleteDog(snapshot.data[index].id),
                    );
                  },
                );
              } else {
                return Container(
                    child: Center(
                  child: Text("Loading..."),
                ));
              }
            },
          ),
        ),
        floatingActionButton: Visibility(
          visible: show,
          child: Stack(
            children: <Widget>[
              Padding(
                padding: EdgeInsets.only(left: 30),
                child: Align(
                  alignment: Alignment.bottomLeft,
                  child: FloatingActionButton(
                    onPressed: () {
                      setState(() {future = getDogs();});
                    },
                    child: Icon(Icons.refresh),
                  ),
                ),
              ),
              Align(
                alignment: Alignment.bottomRight,
                child: FloatingActionButton(
                  onPressed: _insertDog,
                  tooltip: 'Increment',
                  child: Icon(Icons.add),
                ),
              ),
            ],
          ),
        ));
  }

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM