簡體   English   中英

從有狀態小部件更新無狀態小部件

[英]Updating a Stateless Widget from a Stateful Widget

主.dart:

import 'package:flutter/material.dart';
import 'package:mypackage/widgets/home_widget.dart';

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

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: "My App",
      theme: ThemeData(primarySwatch: Colors.blueGrey),
      home: Home(),
    );
  }
}

主頁.dart:

import 'package:flutter/material.dart';
import 'package:mypackage/widgets/secondary_page.dart';
import 'package:mypackage/widgets/home_view.dart';
import 'package:mypackage/widgets/settings_page.dart';

class Home extends StatefulWidget {
  @override
  State<StatefulWidget> createState() {
    return _HomeState();
  }
}

class _HomeState extends State<Home> {
  int currentPageIndex = 0;
  final List<Widget> pageWidgets = [HomeView(), SecondaryPage(), SettingsPage()];

  @override
  Widget build(BuildContext context) {
    return Scaffold(
        appBar: AppBar(
          title: Text("My App"),
          centerTitle: true,
        ),
        body: pageWidgets[currentPageIndex],
        bottomNavigationBar: BottomNavigationBar(
          onTap: onTabTapped,
          currentIndex: currentPageIndex,
          items: [
            BottomNavigationBarItem(
                icon: new Icon(Icons.home), label: "Tab One"),
            BottomNavigationBarItem(
                icon: new Icon(Icons.account_balance), label: "Tab Two"),
            BottomNavigationBarItem(
                icon: new Icon(Icons.settings), label: "Tab Three"),
          ],
        ),
        floatingActionButton: FloatingActionButton(onPressed: () {
          // Update data from here
          HomeView().updateDisplay();
        }));
  }

  // Changes the index when the tapped page has loaded
  void onTabTapped(int index) {
    setState(() {
      currentPageIndex = index;
    });
  }
}

主頁查看.dart:

import 'package:flutter/material.dart';
import 'package:mypackage/models/mydisplay.dart';
import 'package:mypackage/network/mydata.dart';

class HomeView extends StatelessWidget {
  final List<MyDisplay> dataList = [
    new MyDisplay("Sample Display",
        "SampleFile", 0),
  ];

  Future<void> updateDisplay() async {
    MyData myData = new MyData();

    dataList.forEach((d) async {
      d.changePercentage = await myData
          .getDataPercentage("assets/data/" + d.fileName + ".xml");

      print(d.dataName +
          " change percentage: " +
          d.changePercentage.toString() +
          "%");
    });
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: new ListView.builder(
          itemCount: dataList.length,
          itemBuilder: (BuildContext context, int index) =>
              buildCard(context, index)),
    );
  }

  Widget buildCard(BuildContext context, int index) {
    return Container(
        child: Card(
            color: Colors.teal.shade200,
            child: Padding(
                padding: const EdgeInsets.all(25),
                child: Column(children: <Widget>[
                  Text(dataList[index].dataName,
                      style: new TextStyle(
                          fontSize: 20, fontWeight: FontWeight.bold)),
                  Text(dataList[index].changePercentage.toString() + "%")
                ]))));
  }
}

當我從 floatingActionButton 調用 updateDisplay() 方法時,它按預期工作,數據被打印到控制台,但是它似乎沒有更新實際的 UI,卡片的內容,它們只是保持在初始設置值.

澄清一下:如何從有狀態小部件更新列表視圖內(無狀態小部件內)的卡片內容?

如果這是一個重復的問題,我很抱歉,我已經查看並繼續尋找問題的答案,但我根本無法讓它工作。

您需要使用有狀態小部件,因為您無法更新無狀態小部件。 查看鏈接以獲取更多信息。下一個問題,調用它,可以通過使用 globalKeys 來修復。 唯一奇怪的是,您必須將 Home 有狀態小部件和 HomeView 有狀態小部件保存在同一個 dart 文件中。 . 試試這個代碼讓它工作。

主頁視圖

import 'package:flutter/material.dart';
import 'package:mypackage/widgets/secondary_page.dart';
import 'package:mypackage/widgets/settings_page.dart';
import 'package:mypackage/models/mydisplay.dart';
import 'package:mypackage/network/mydata.dart';

class Home extends StatefulWidget {
  @override
  State<StatefulWidget> createState() {
    return _HomeState();
  }
}

class _HomeState extends State<Home> {
  int currentPageIndex = 0;
  final List<Widget> pageWidgets = [HomeView(), SecondaryPage(), SettingsPage()];
  GlobalKey<_HomeViewState> _myKey = GlobalKey();// We declare a key here
  @override
  Widget build(BuildContext context) {
    return Scaffold(
        appBar: AppBar(
          title: Text("My App"),
          centerTitle: true,
        ),
        body: pageWidgets[currentPageIndex],
        bottomNavigationBar: BottomNavigationBar(
          onTap: onTabTapped,
          currentIndex: currentPageIndex,
          items: [
            BottomNavigationBarItem(
                icon: new Icon(Icons.home), label: "Tab One"),
            BottomNavigationBarItem(
                icon: new Icon(Icons.account_balance), label: "Tab Two"),
            BottomNavigationBarItem(
                icon: new Icon(Icons.settings), label: "Tab Three"),
          ],
        ),
        floatingActionButton: FloatingActionButton(onPressed: () {
          // Update data from here
          _myKey.currentState.updateDisplay();//This is how we call the function
        }));
  }

  // Changes the index when the tapped page has loaded
  void onTabTapped(int index) {
    setState(() {
      currentPageIndex = index;
    });
  }
}

class HomeView extends StatefulWidget {
  Function updateDisplay;
  HomeView({Key key}): super(key: key);//This key is what we use
  @override
  _HomeViewState createState() => _HomeViewState();
}

class _HomeViewState extends State<HomeView> {
  final List<MyDisplay> dataList = [
    new MyDisplay("Sample Display",
        "SampleFile", 0),
  ];

@override
  void initState(){
    super.initState();
    widget.updateDisplay = () async {
      MyData myData = new MyData();

      dataList.forEach((d) async {
        d.changePercentage = await myData
            .getDataPercentage("assets/data/" + d.fileName + ".xml");
        print(d.dataName +
            " change percentage: " +
            d.changePercentage.toString() +
            "%");
      });
      setState((){});//This line rebuilds the scaffold
    };
  }
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: new ListView.builder(
          itemCount: dataList.length,
          itemBuilder: (BuildContext context, int index) =>
              buildCard(context, index)),
    );
  }

  Widget buildCard(BuildContext context, int index) {
    return Container(
        child: Card(
            color: Colors.teal.shade200,
            child: Padding(
                padding: const EdgeInsets.all(25),
                child: Column(children: <Widget>[
                  Text(dataList[index].dataName,
                      style: new TextStyle(
                          fontSize: 20, fontWeight: FontWeight.bold)),
                  Text(dataList[index].changePercentage.toString() + "%")
                ]))));
  }
}

我們使用 setState((){}) 來重建小部件。 只要記住一個想法。 無論您在哪里使用 updateDisplay 方法,都不要讓它在重建后循環運行。 例如。 您在孩子內部的未來構建器中使用它。 這樣它將繼續重建

編輯

我們向 HomeView 添加了一個鍵,現在我們可以像_myKey.currentState.yourFunction一樣使用該鍵。 希望我有所幫助

雖然我了解您希望實現的目標,但我相信這將違背“Flutter 方式”。 您可以使用一個鍵來實現您想要的結果,但我相信將 state 提升到小部件樹上會更容易和更慣用。 您可以在此處的文檔中閱讀有關它的信息。

因此,在您的情況下,您可以將其更改為:

class Home extends StatefulWidget {
  @override
  State<StatefulWidget> createState() {
    return _HomeState();
  }
}

class _HomeState extends State<Home> {
  int currentPageIndex = 0;
  // Added this line
  List<MyDisplay> dataList = [
    new MyDisplay("Sample Display",
        "SampleFile", 0),
  ];

  final List<Widget> pageWidgets; 

  // moved the update function from HomeView to here
  Future<void> updateDisplay() async {
    MyData myData = new MyData();

    dataList.forEach((d) async {
      d.changePercentage = await myData
          .getDataPercentage("assets/data/" + d.fileName + ".xml");

      print(d.dataName +
          " change percentage: " +
          d.changePercentage.toString() +
          "%");
    });
    setState((){});
  }

  @override
  Widget build(BuildContext context) {
    pageWidgets = [HomeView(dataList: dataList), SecondaryPage(), SettingsPage()]

    return Scaffold(
        appBar: AppBar(
          title: Text("My App"),
          centerTitle: true,
        ),
        body: pageWidgets[currentPageIndex],
        bottomNavigationBar: BottomNavigationBar(
          onTap: onTabTapped,
          currentIndex: currentPageIndex,
          items: [
            BottomNavigationBarItem(
                icon: new Icon(Icons.home), label: "Tab One"),
            BottomNavigationBarItem(
                icon: new Icon(Icons.account_balance), label: "Tab Two"),
            BottomNavigationBarItem(
                icon: new Icon(Icons.settings), label: "Tab Three"),
          ],
        ),
        floatingActionButton: FloatingActionButton(onPressed: () {
          updateDisplay();
        }));
  }

  // Changes the index when the tapped page has loaded
  void onTabTapped(int index) {
    setState(() {
      currentPageIndex = index;
    });
  }
}

然后對於您的 HomeView 小部件:

class HomeView extends StatelessWidget {
  HomeView({this.dataList});

  final List<MyDisplay> dataList;

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: new ListView.builder(
          itemCount: dataList.length,
          itemBuilder: (BuildContext context, int index) =>
              buildCard(context, index)),
    );
  }

  Widget buildCard(BuildContext context, int index) {
    return Container(
        child: Card(
            color: Colors.teal.shade200,
            child: Padding(
                padding: const EdgeInsets.all(25),
                child: Column(children: <Widget>[
                  Text(dataList[index].dataName,
                      style: new TextStyle(
                          fontSize: 20, fontWeight: FontWeight.bold)),
                  Text(dataList[index].changePercentage.toString() + "%")
                ],
              ),
            ),
          ),
        );
  }
}

我還沒有測試這是否有效。 我可能稍后會。

你需要調用setState(() {}); HomeView().updateDisplay();

更新你的 home.dart 如下。

import 'package:flutter/material.dart';
import 'package:mypackage/widgets/secondary_page.dart';
import 'package:mypackage/widgets/home_view.dart';
import 'package:mypackage/widgets/settings_page.dart';

class Home extends StatefulWidget {
  @override
  State<StatefulWidget> createState() {
    return _HomeState();
  }
}

class _HomeState extends State<Home> {
  int currentPageIndex = 0;
  Widget _homeView = HomeView();
  final List<Widget> pageWidgets = [_homeView, SecondaryPage(), SettingsPage()];

  @override
  Widget build(BuildContext context) {
    return Scaffold(
        appBar: AppBar(
          title: Text("My App"),
          centerTitle: true,
        ),
        body: pageWidgets[currentPageIndex],
        bottomNavigationBar: BottomNavigationBar(
          onTap: onTabTapped,
          currentIndex: currentPageIndex,
          items: [
            BottomNavigationBarItem(
                icon: new Icon(Icons.home), label: "Tab One"),
            BottomNavigationBarItem(
                icon: new Icon(Icons.account_balance), label: "Tab Two"),
            BottomNavigationBarItem(
                icon: new Icon(Icons.settings), label: "Tab Three"),
          ],
        ),
        floatingActionButton: FloatingActionButton(onPressed: () {
          // Update data from here
          _homeView.updateDisplay();
        }));
  }

  // Changes the index when the tapped page has loaded
  void onTabTapped(int index) {
    setState(() {
      currentPageIndex = index;
    });
  }
}

home_view.dart如下

import 'package:flutter/material.dart';
import 'package:mypackage/models/mydisplay.dart';
import 'package:mypackage/network/mydata.dart';

class HomeView extends StatelessWidget {
  final List<MyDisplay> dataList = [
    new MyDisplay("Sample Display",
        "SampleFile", 0),
  ];

  Future<void> updateDisplay() async {
    MyData myData = new MyData();

    dataList.forEach((d) async {
      d.changePercentage = await myData
          .getDataPercentage("assets/data/" + d.fileName + ".xml");

      print(d.dataName +
          " change percentage: " +
          d.changePercentage.toString() +
          "%");
    });
     setState((){});
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: new ListView.builder(
          itemCount: dataList.length,
          itemBuilder: (BuildContext context, int index) =>
              buildCard(context, index)),
    );
  }

  Widget buildCard(BuildContext context, int index) {
    return Container(
        child: Card(
            color: Colors.teal.shade200,
            child: Padding(
                padding: const EdgeInsets.all(25),
                child: Column(children: <Widget>[
                  Text(dataList[index].dataName,
                      style: new TextStyle(
                          fontSize: 20, fontWeight: FontWeight.bold)),
                  Text(dataList[index].changePercentage.toString() + "%")
                ]))));
  }
}

您需要將HomeView轉換為StatefulWidget

之后,您需要將updateDisplay修改為:

Future<void> updateDisplay() async {
    MyData myData = new MyData();

    dataList.forEach((d) async {
      d.changePercentage = await myData
          .getDataPercentage("assets/data/" + d.fileName + ".xml");

      print(d.dataName +
          " change percentage: " +
          d.changePercentage.toString() +
          "%");
    });
    
    setState(() {});
  }

通過調用setState (() {}); 您在StatefulWidget中調用 build 方法。

編輯

像這樣更改您的HomeView

class HomeView extends StatefulWidget {
  final List<MyDisplay> dataList = [
    new MyDisplay("Sample Display",
        "SampleFile", 0),
  ];

  Future<void> updateDisplay() async {
    MyData myData = new MyData();

    dataList.forEach((d) async {
      d.changePercentage = await myData
          .getDataPercentage("assets/data/" + d.fileName + ".xml");

      print(d.dataName +
          " change percentage: " +
          d.changePercentage.toString() +
          "%");
    });
  }
  @override
  _HomeViewState createState() => _HomeViewState();
}

class _HomeViewState extends State<HomeView> {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: new ListView.builder(
          itemCount: widget.dataList.length,
          itemBuilder: (BuildContext context, int index) =>
              buildCard(context, index)),
    );
  }

  Widget buildCard(BuildContext context, int index) {
    return Container(
        child: Card(
            color: Colors.teal.shade200,
            child: Padding(
                padding: const EdgeInsets.all(25),
                child: Column(children: <Widget>[
                  Text(widget.dataList[index].dataName,
                      style: new TextStyle(
                          fontSize: 20, fontWeight: FontWeight.bold)),
                  Text(widget.dataList[index].changePercentage.toString() + "%")
                ]))));
  }
}

你的Home是這樣的:

class Home extends StatefulWidget {
  @override
  State<StatefulWidget> createState() {
    return _HomeState();
  }
}

class _HomeState extends State<Home> {
  int currentPageIndex = 0;
  HomeView _homeView = HomeView();
  List<Widget> pageWidgets = [_homeView, SecondaryPage(), SettingsPage()];

  @override
  Widget build(BuildContext context) {
    return Scaffold(
        appBar: AppBar(
          title: Text("My App"),
          centerTitle: true,
        ),
        body: pageWidgets[currentPageIndex],
        bottomNavigationBar: BottomNavigationBar(
          onTap: onTabTapped,
          currentIndex: currentPageIndex,
          items: [
            BottomNavigationBarItem(
                icon: new Icon(Icons.home), label: "Tab One"),
            BottomNavigationBarItem(
                icon: new Icon(Icons.account_balance), label: "Tab Two"),
            BottomNavigationBarItem(
                icon: new Icon(Icons.settings), label: "Tab Three"),
          ],
        ),
        floatingActionButton: FloatingActionButton(onPressed: () {
          // Update data from here
          _homeView.updateDisplay();
        }));
  }

  // Changes the index when the tapped page has loaded
  void onTabTapped(int index) {
    setState(() {
      currentPageIndex = index;
    });
  }
}

暫無
暫無

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

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