如何在 Flutter 的 StatefulWidget 类中的 setState() 方法上停止小部件重新加载

Posted

技术标签:

【中文标题】如何在 Flutter 的 StatefulWidget 类中的 setState() 方法上停止小部件重新加载【英文标题】:How to stop a widget to reload on setState() method in StatefulWidget Class in Flutter 【发布时间】:2020-06-07 23:38:28 【问题描述】:

我想要实现的是保存 Widget 的状态,即在调用 setState() 方法时它不应该刷新。

class _GenderSelectionPageState extends State<GenderSelectionPage> 
  bool isFemaleSelected = false;
  AdmobBannerSize bannerSize;
  GlobalKey _globalKey = new GlobalKey();

  bool isLoaded = false;

  @override
  void initState() 
    // TODO: implement initState
    super.initState();
    bannerSize = AdmobBannerSize.BANNER;
  

  @override
  Widget build(BuildContext context) 
    double height = MediaQuery.of(context).size.height;
    double width = MediaQuery.of(context).size.width;

    return new Scaffold(
      body: new Container(
          width: width,
          child: new Center(
            child: Column(
              mainAxisAlignment: MainAxisAlignment.end,
              children: <Widget>[
                Expanded(
                  child: Column(
                    mainAxisAlignment: MainAxisAlignment.center,
                    mainAxisSize: MainAxisSize.max,
                    children: <Widget>[
                      Flexible(
                        child: new Hero(
                          tag: "gender",
                          child: Material(
                            child: new Row(
                              children: <Widget>[
                                InkWell(
                                  onTap: () 
                                    setState(() 
                                      if (isFemaleSelected) 
                                        isFemaleSelected = false;
                                       else 
                                        isFemaleSelected = true;
                                      
                                    );
                                  ,
                                  child: Opacity(
                                    child: Image.asset(
                                      "assets/woman.png",
                                      height: height / 4,
                                      width: width / 2 - 12,
                                    ),
                                    opacity: isFemaleSelected ? 1.0 : 0.30,
                                  ),
                                ),
                                InkWell(
                                  onTap: () 
                                    setState(() 
                                      if (isFemaleSelected) 
                                        isFemaleSelected = false;
                                       else 
                                        isFemaleSelected = true;
                                      
                                    );
                                  ,
                                  child: Opacity(
                                    opacity: !isFemaleSelected ? 1.0 : 0.30,
                                    child: Image.asset(
                                      "assets/boy.png",
                                      height: height / 4,
                                      width: width / 2 - 12,
                                    ),
                                  ),
                                ),
                              ],
                            ),
                          ),
                        ),
                      ),
                    ],
                  ),
                  flex: 1,
                ),
                InkWell(
                    onTap: () 
                      setState(() 

                      );
                      Navigator.push(
                          context,
                          MaterialPageRoute(
                              builder: (BuildContext) =>
                                  new HeightWeightSelection(isFemaleSelected
                                      ? "assets/woman.png"
                                      : "assets/boy.png")));
                    ,
                    child: Container(
                      margin: EdgeInsets.only(bottom: 12.0),
                      child: new Image.asset(
                        "assets/next.png",
                        height: 64.0,
                        width: 64.0,
                      ),
                    )),
                new AdmobBannerWrapper(adUnitId: getBannerAdUnitId(),adSize: bannerSize,key: _globalKey,),
               /* new AdmobBanner(
                  adUnitId: getBannerAdUnitId(),
                  adSize: bannerSize,
                  listener:
                      (AdmobAdEvent event, Map<String, dynamic> args) 
                    handleEvent(event, args, 'Banner');
                  ,
                ),*/
              ],
            ),
          )),
    );
  

我不想每次按下底部的图像按钮时都调用 AdmobBannerWrapper。AdmobBannerWrapper 应该只加载一次,但问题是每当我单击 Next Image 时,它​​每次都会加载 AdmobBannerWrapper 方法。

【问题讨论】:

如果您不想再次重建 AdmobBannerWrapper,则将该小部件移动到父小部件中。 谢谢 Darish,但我的父小部件是 Column 包裹在 Statefull 类的 Scaffold 中。 不清楚为什么要将 AdmobBannerWrapper 保留在子小部件中。你能解释一下你的用例吗? 等一下,我会上传我的整个课程,以便您更好地理解它。 (adUnitId: getBannerAdUnitId() 不要那样做。您可能想阅读***.com/questions/52249578/… 【参考方案1】:

initState() 中构建它,然后在需要的地方使用它的引用它不会再次构建,直到父小部件重新初始化。

  var banner;

  @override
  void initState() 
    // TODO: implement initState
    super.initState();
    bannerSize = AdmobBannerSize.BANNER;
    banner = AdmobBannerWrapper(adUnitId: getBannerAdUnitId(),adSize: bannerSize,key:_globalKey,);
  

而不是在这里引用banner


  @override
  Widget build(BuildContext context) 
    double height = MediaQuery.of(context).size.height;
    double width = MediaQuery.of(context).size.width;

    return new Scaffold(
      body: new Container(
          width: width,
          child: new Center(
            child: Column(
              mainAxisAlignment: MainAxisAlignment.end,
              children: <Widget>[
                Expanded(
                  child: Column(
                    mainAxisAlignment: MainAxisAlignment.center,
                    mainAxisSize: MainAxisSize.max,
                    children: <Widget>[
                      Flexible(
                        child: new Hero(
                          tag: "gender",
                          child: Material(
                            child: new Row(
                              children: <Widget>[
                                InkWell(
                                  onTap: () 
                                    setState(() 
                                      if (isFemaleSelected) 
                                        isFemaleSelected = false;
                                       else 
                                        isFemaleSelected = true;
                                      
                                    );
                                  ,
                                  child: Opacity(
                                    child: Image.asset(
                                      "assets/woman.png",
                                      height: height / 4,
                                      width: width / 2 - 12,
                                    ),
                                    opacity: isFemaleSelected ? 1.0 : 0.30,
                                  ),
                                ),
                                InkWell(
                                  onTap: () 
                                    setState(() 
                                      if (isFemaleSelected) 
                                        isFemaleSelected = false;
                                       else 
                                        isFemaleSelected = true;
                                      
                                    );
                                  ,
                                  child: Opacity(
                                    opacity: !isFemaleSelected ? 1.0 : 0.30,
                                    child: Image.asset(
                                      "assets/boy.png",
                                      height: height / 4,
                                      width: width / 2 - 12,
                                    ),
                                  ),
                                ),
                              ],
                            ),
                          ),
                        ),
                      ),
                    ],
                  ),
                  flex: 1,
                ),
                InkWell(
                    onTap: () 
                      setState(() 

                      );
                      Navigator.push(
                          context,
                          MaterialPageRoute(
                              builder: (BuildContext) =>
                                  new HeightWeightSelection(isFemaleSelected
                                      ? "assets/woman.png"
                                      : "assets/boy.png")));
                    ,
                    child: Container(
                      margin: EdgeInsets.only(bottom: 12.0),
                      child: new Image.asset(
                        "assets/next.png",
                        height: 64.0,
                        width: 64.0,
                      ),
                    )),
                banner, /*this is our variable */
               /* new AdmobBanner(
                  adUnitId: getBannerAdUnitId(),
                  adSize: bannerSize,
                  listener:
                      (AdmobAdEvent event, Map<String, dynamic> args) 
                    handleEvent(event, args, 'Banner');
                  ,
                ),*/
              ],
            ),
          )),
    );
  

【讨论】:

是的,现在也这样做了。谢谢:) 知道如何使用键来实现这一点吗? 一旦父小部件默认构建它,键在这里将无济于事。 你才是真正的英雄!!!太感谢了。它几乎救了我的命 最佳方法!... 工作得很好。非常感谢您的回答【参考方案2】:

将其放入无状态小部件中:

class AdBanner extends StatelessWidget
  final adUnitId;
  final adSize;

  const AdBanner(Key key, this.adUnitId, this.adSize) : super(key: key);

  Widget build(BuildContext context)
    return AdmobBannerWrapper(
      adUnitId: getBannerAdUnitId(),
      adSize: bannerSize,
      key: _globalKey,
      );
  

下次调用setState时,如果参数不变,就不会重建了。

【讨论】:

可以将此无状态小部件作为有状态小部件构建小部件树层次结构的一部分调用吗??

以上是关于如何在 Flutter 的 StatefulWidget 类中的 setState() 方法上停止小部件重新加载的主要内容,如果未能解决你的问题,请参考以下文章

Flutter - 如何在 Flutter 应用上实现 News Count

Flutter:如何在 Flutter 中为 Firebase (FCM) 注册令牌订阅ToTopic

Flutter:如何在 google_maps_flutter 中为标记图标设置动画?

Flutter :: 如何在showTimePicker中限制时间?

flutter - 如何在 dart/flutter 中收听流值

如何在flutter中使用flutter_webview_plugin和AndroidX