setState 不更新 UI

时间:2021-02-19 10:06:41

标签: flutter setstate sliverappbar

我正在使用 CustomScrollView 并尝试在 SliverAppBar 操作中添加一个喜欢按钮,通过点击它,它的形状会发生变化。我正在 setState 内进行更改。但是尽管调用了 build 方法,但 UI 并未更新。

TextButton(
  onPressed: () {
     bool added = courseStore.addToUserFavoriteCourses(widget.courseDetails);
     added ?
       setState(() {
         iconData = Icons.favorite;
       }) :
       setState(() {
         iconData = Icons.favorite_border;
       });
  },
  child: Icon(
     iconData,
     size: 20,
     color: Colors.white,
  ),
)

1 个答案:

答案 0 :(得分:1)

上面的代码还没有保存 iconData 的状态。

喜欢/不喜欢的状态需要向上移动到小部件范围内。然后可以在子级下面引用它的值,例如 TextButton。

当 TextButton 被重建(从不喜欢变为喜欢和返回)时,它可以使用它上面持续存在的状态。

请注意以下 iconData 是如何存在于 State 小部件中的。此小部件旨在为其子项保持状态。

您可以将此代码复制粘贴到 Flutter/Dart 文件中进行测试:

import 'package:flutter/material.dart';

// ↓ Use this as your button
class StatefulButton extends StatefulWidget {
  final double size;
  final Color color;

  StatefulButton({this.size = 20, this.color = Colors.black});

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

class _StatefulButtonState extends State<StatefulButton> {
  IconData iconData = Icons.favorite_border;
  // ↑ Move your state up to here

  @override
  Widget build(BuildContext context) {
    return Center(
      child: TextButton(
        child: Icon(
          iconData,
          size: widget.size,
          color: widget.color,
        ),
        onPressed: toggleLike,
      ),
    );
  }

  void toggleLike() {
    setState(() {
      iconData = iconData == Icons.favorite ? Icons.favorite_border : Icons.favorite;
    });
  }
}


/// Just a container page for the example above
class TextButtonStatePage extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text('TextButtonState'),
      ),
      body: StatefulButton()
    );
  }
}

以下是在 CustomScrollView 中使用上述 StatefulButton 的示例。我窃取的 CustomScrollView 代码 straight from the Flutter docs website。我所做的唯一编辑是将上面的 StatefulButton 添加到每个条带中,以显示它在单击时更改其状态。

/// Flutter code sample for CustomScrollView

import 'package:flutter/material.dart';
import 'text_button_state.dart';

/// This is the stateful widget that the main application instantiates.
class CustomScrollviewPage extends StatefulWidget {
  CustomScrollviewPage({Key key}) : super(key: key);

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

/// This is the private State class that goes with MyStatefulWidget.
class _CustomScrollviewPageState extends State<CustomScrollviewPage> {
  List<int> top = [];
  List<int> bottom = [0];

  @override
  Widget build(BuildContext context) {
    const Key centerKey = ValueKey('bottom-sliver-list');
    return Scaffold(
      appBar: AppBar(
        title: const Text('Press on the plus to add items above and below'),
        leading: IconButton(
          icon: const Icon(Icons.add),
          onPressed: () {
            setState(() {
              top.add(-top.length - 1);
              bottom.add(bottom.length);
            });
          },
        ),
      ),
      body: CustomScrollView(
        center: centerKey,
        slivers: <Widget>[
          SliverList(
            delegate: SliverChildBuilderDelegate(
                  (BuildContext context, int index) {
                return Container(
                  alignment: Alignment.center,
                  color: Colors.blue[200 + top[index] % 4 * 100],
                  height: 100 + top[index] % 4 * 20.0,
                  child: Row(
                    mainAxisAlignment: MainAxisAlignment.center,
                    children: [
                    Text('Item: ${top[index]}'),
                    StatefulButton() // ← STATEFUL BUTTON HERE
                  ],),
                );
              },
              childCount: top.length,
            ),
          ),
          SliverList(
            key: centerKey,
            delegate: SliverChildBuilderDelegate(
                  (BuildContext context, int index) {
                return Container(
                  alignment: Alignment.center,
                  color: Colors.blue[200 + bottom[index] % 4 * 100],
                  height: 100 + bottom[index] % 4 * 20.0,
                  child: Row(
                    mainAxisAlignment: MainAxisAlignment.center,
                    children: [
                      Text('Item: ${bottom[index]}'),
                      StatefulButton()  // ← STATEFUL BUTTON HERE
                    ],
                  ),
                );
              },
              childCount: bottom.length,
            ),
          ),
        ],
      ),
    );
  }
}