在 StatefulBuilder 小部件之外设置 StatefulBuilder 状态

时间:2021-05-24 11:56:22

标签: flutter dart flutter-layout

我正在尝试在其小部件之外设置一个 StatefulBuilder 小部件状态。大多数示例和可用文档都显示了在小部件内部使用的 setState 方法,但是我想知道是否可以从 StatefulBuilder 小部件外部调用此类方法。举个例子:

import 'package:flutter/material.dart';

void main() {
  runApp(MyApp());
}

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'StackOverflow Example',
      theme: ThemeData(
        primarySwatch: Colors.blue,
      ),
      home: MyHomePage(title: 'StackOverflow Example'),
    );
  }
}

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

  final String title;

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

class _MyHomePageState extends State<MyHomePage> {
  @override
  Widget build(BuildContext context) {
    return new GestureDetector(
      //Change one of the icon's color using the tap down function
      onTapDown: (TapDownDetails details) {
        return changeColor(details);
      },
      child: Scaffold(
        appBar: AppBar(
          title: Text('Example'),
        ),
        body: Center(
          child: Column(children: [
            //This widget should be rebuilt
            StatefulBuilder(
                builder: (BuildContext context, StateSetter setState)
                {
                  Color _iconColor = Colors.black;
                  return Icon(
                    Icons.money,
                    size: 50,
                    color: _iconColor,
                  );
                }
            ),
            //This icon should not be rebuilt
            Icon(
              Icons.euro,
              size: 50,
              color: Colors.black,
            ),
          ]),
        ),
      ),
    );
  }

  void changeColor(TapDownDetails details) {
    //Rebuilt StatefulBuilder widget here, but how?
    setState(() {
      _iconColor = Colors.green;
    });
  }


}

目前我收到一个错误,因为 _iconColor 中使用了 setState 变量。我也知道可能无法在小部件之外访问它。如果是这种情况,在不诉诸重建整个 StatefulWidget 的情况下更改图标颜色的更好解决方案是什么?

感谢您的时间。

2 个答案:

答案 0 :(得分:2)

您可以使用 ValueListenableBuilder 小部件。
示例:

import 'package:flutter/material.dart';

void main() {
  runApp(MyApp());
}

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'StackOverflow Example',
      theme: ThemeData(
        primarySwatch: Colors.blue,
      ),
      home: MyHomePage(title: 'StackOverflow Example'),
    );
  }
}

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

  final String title;

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

class _MyHomePageState extends State<MyHomePage> {
  ValueNotifier _iconColor = ValueNotifier<Color>(Colors.black);
  
  @override
  Widget build(BuildContext context) {
    return new GestureDetector(
      //Change one of the icon's color using the tap down function
      onTapDown: (TapDownDetails details) {
        return changeColor(details);
      },
      child: Scaffold(
        appBar: AppBar(
          title: Text('Example'),
        ),
        body: Center(
          child: Column(children: [
            //This widget should be rebuilt
            ValueListenableBuilder(
            valueListenable: _iconColor,
              builder: (ctx, value, child) {
               return Icon(
                    Icons.money,
                    size: 50,
                    color: value,
                  );
              }
            ),
            //This icon should not be rebuilt
            Icon(
              Icons.euro,
              size: 50,
              color: Colors.black,
            ),
          ]),
        ),
      ),
    );
  }

  void changeColor(TapDownDetails details) =>
    _iconColor.value = Colors.green
}

答案 1 :(得分:1)

如果您一定要使用 StatefulBuilder,这是实现您的意图的一种方法。

基本上,我们正在存储从 StateSetter 接收到的 StatefulBuilder.builder

class Sample extends StatefulWidget {
  @override
  State<StatefulWidget> createState() {
    return SampleState();
  }
}

class SampleState extends State<Sample> {
  StateSetter internalSetter;
  Color color = Colors.black;

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      resizeToAvoidBottomInset: false,
      appBar: AppBar(title: Text('Sample')),
      body: Column(
        children: [
          GestureDetector(
            onTap: () {
              setState(() {
                color = Colors.deepOrange;
              });
            },
            child: Text('Press'),
          ),
          StatefulBuilder(builder: (context, setter) {
            internalSetter = setter;
            return Container(
              height: 100,
              width: 100,
              color: color,
            );
          }),
          Undisturbed(),
        ],
      ),
    );
  }
}

class Undisturbed extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    print("Undisturbed is built");
    return Container(
      width: 100,
      height: 100,
      color: Colors.red,
    );
  }
}