Flutter Slider 未在 ExpansionPanel 内部重建

Posted

技术标签:

【中文标题】Flutter Slider 未在 ExpansionPanel 内部重建【英文标题】:Flutter Slider not rebuilding inside of ExpansionPanel 【发布时间】:2020-04-08 04:30:10 【问题描述】:

我正在尝试在 ExpansionPanelList 中使用多个 ExpansionPanels 创建一个表单。 我最初使用initState 在页面中设置表单。

现在我遇到的主要问题是将Slider 小部件实现到ExpansionPanel 之一。 Slider 按钮 UI 不会在更改时更新,但滑块的值 _colorValue 是。

我认为问题在于 ExpansionPanel body 在重建时没有更新,但我不确定如何解决它。 我已经在没有真正帮助的情况下阅读了文档。

这是我的代码:

import ...

/// stores ExpansionPanel state information
class Panel 
  Panel(
    this.expandedValue,
    this.headerValue,
    this.isExpanded = false,
  );

  Widget expandedValue;
  String headerValue;
  bool isExpanded;


class AddReviewScreen extends StatefulWidget 
  static const String route = 'add_review_screen';
  @override
  _AddReviewScreenState createState() => _AddReviewScreenState();


class _AddReviewScreenState extends State<AddReviewScreen> 
  final _formKey = GlobalKey<FormState>();
  double _colorValue = 1.0;
  List<Panel> _panels;

  @override
  void initState() 
    super.initState();
    _panels = _getPanels();
  

  @override
  Widget build(BuildContext context) 
    return Scaffold(
      appBar: AppBar(
        centerTitle: true,
        title: Text('Add Review', style: Theme.of(context).textTheme.display4),
        backgroundColor: kAppBarBackgroundColor,
      ),
      backgroundColor: kScaffoldBackgroundColor,
      body: SafeArea(
        child: SingleChildScrollView(
          child: Container(
            padding: EdgeInsets.all(8.0),
            child: Form(
              key: _formKey,
              child: _buildForm(),
            ),
          ),
        ),
      ),
    );
  

  List<Panel> _getPanels() 
    return [
      Panel(...),
      Panel(
        headerValue: 'Sensory Features',
        expandedValue: Column(
          children: <Widget>[
            Slider(
              value: _colorValue,
              min: 0.0,
              max: 2.0,
              divisions: 20,
              onChanged: (double newValue) 
                setState(() 
                  _colorValue = newValue;
                  print(_colorValue);
                );
              ,
            ),
            TextFormField(...),
            TextFormField(...),
            TextFormField(...),
          ],
        ),
      ),
    ];
  

  Widget _buildForm() 
    return ExpansionPanelList(
      expansionCallback: (int index, bool isExpanded) 
        setState(() 
          _panels[index].isExpanded = !isExpanded;
        );
      ,
      children: _panels.map<ExpansionPanel>((Panel panel) 
        return ExpansionPanel(
          headerBuilder: (BuildContext context, bool isExpanded) 
            return ListTile(
              title: Text(panel.headerValue),
            );
          ,
          body: panel.expandedValue,
          isExpanded: panel.isExpanded,
        );
      ).toList(),
    );
  


任何帮助将不胜感激! 如果有任何问题,请告诉我,我会尽力解答。

【问题讨论】:

【参考方案1】:

问题和我想的一样,在body: panel.expandedValue 行。每当触发重建时,面板就会从 _panels 列表中重新绘制,因此会返回到它们的初始状态。

我如何设法解决它是首先从_getPanels 的面板中提取每个expandedValue 到它们自己的单独函数中。然后,我将 ExpansionPanelList 的子项从动态 Map/List 重构为 ExpansionPanels 的静态列表,因为我知道列表的大小将来不会改变,因此没有理由动态功能。

因此,基本上现在无论何时发生重建,UI 都不会回退到其初始状态。相反,它会更新提取的 Widget 函数中的“脏”值。

这是我的解决方案:

  /// Construct the initial List of Panels.
  List<Panel> _getPanels() 
    return [
      Panel(
        headerValue: 'Panel 1',
        expandedValue: _panel1(),
        isExpanded: true,
      ),
      Panel(
        headerValue: 'Panel 2',
        expandedValue: _panel2(),
      ),
    ];
  

  Function _expansionPanelHeaderBuilderCallback(String title) 
    return (BuildContext context, bool isExpanded) 
      return ListTile(
        title: Text(title),
      );
    ;
  

  Widget _buildForm() 
    return ExpansionPanelList(
      expansionCallback: (int index, bool isExpanded) 
        setState(() 
          _panels[index].isExpanded = !isExpanded;
        );
      ,
      children: [
        ExpansionPanel(
          headerBuilder: _expansionPanelHeaderBuilderCallback(_panels[0].headerValue),
          body: _panel1(),
          isExpanded: _panels[0].isExpanded,
          canTapOnHeader: true,
        ),
        ExpansionPanel(
          headerBuilder:
              _expansionPanelHeaderBuilderCallback(_panels[1].headerValue),
          body: _panel2(),
          isExpanded: _panels[1].isExpanded,
          canTapOnHeader: true,
        ),
      ],
    );
  

  Widget _panel1() 
    return Padding(...);
  

  Widget _panel2() 
    return Column(...);
  

如果找到更好的解决方案(我确信有),请在此处发布,我会将其标记为正确答案。

【讨论】:

以上是关于Flutter Slider 未在 ExpansionPanel 内部重建的主要内容,如果未能解决你的问题,请参考以下文章

iOS 设备中 Flutter TabBarView 覆盖底部区域(Slider)

Flutter Slider - 不显示标签

Flutter 121: 图解简易 Slider 滑动条

Flutter 应用程序创建一个扩展面板列表

Flutter ExpansionPanelList - 扩展回调不起作用

为每个页面创建具有动态高度的 Flutter Carousel Slider