将更新状态发送给子小部件颤动

时间:2020-03-07 22:36:31

标签: flutter flutter-state

我有一个父窗口小部件,其中包含项目列表和所选项目的索引。子窗口小部件告诉父项何时选择了一项。如果我将isSelected(index)函数传递给子窗口小部件,则子窗口小部件将更新以显示选择了哪个项目。如果我将selectedIndex int传递给子窗口小部件,则selectedIndex在父级而不是子级中更新。

使用isSelected(index)函数的工作版本

import 'package:flutter/material.dart';

class IsSelected extends StatefulWidget {
  @override
  State<StatefulWidget> createState() => IsSelectedState();
}

class IsSelectedState extends State<IsSelected> {
  List<int> _items = List.from([0]);
  int _selectedIndex = -1;

  @override
  Widget build(BuildContext context) {
    return SafeArea(
      child: Column(
        children: <Widget>[
          Row(
            children: <Widget>[
              IconButton(
                icon: Icon(Icons.indeterminate_check_box),
                onPressed: () {
                  setState(() {
                    _items.removeAt(_selectedIndex);
                  });
                }
              ),
              IconButton(
                icon: Icon(Icons.add_box),
                onPressed: () {
                  setState(() {
                    _items.add(_items.length);
                  });
                }
              )
            ]
          ),
          Expanded(
            child: ItemList(
              items: _items,
              isSelected: (index) => _selectedIndex == index,
              onSelect: (index) => setState(() {
                _selectedIndex = index;
              })
            )
          )
        ],
      )
    );
  }
}

class ItemList extends StatefulWidget {
  final List<int> _items;
  final Function _isSelected;
  final Function _onSelect;

  ItemList({items, isSelected, onSelect}) :
    _items = items,
    _isSelected = isSelected,
    _onSelect = onSelect;

  @override
  State<StatefulWidget> createState() => ItemListState(
    items: _items,
    isSelected: _isSelected,
    onSelect: _onSelect
  );
}

class ItemListState extends State<ItemList> {
  final List<int> _items;
  final Function _isSelected;
  final Function _onSelect;


  ItemListState({items, isSelected, onSelect}) :
    _items = items,
    _isSelected = isSelected,
    _onSelect = onSelect;

  @override
  Widget build(BuildContext context) {
    return ListView.builder(
      itemCount: _items.length,
      itemBuilder: (BuildContext context, int index) {
        // I used a withOpacity(0) below to make the border transparent
        // The background colors of the ListView isn't quite white
        final Color borderColor = _isSelected(index) ?
          Theme.of(context).primaryColor : Colors.white.withOpacity(0);
        return GestureDetector(
          onTap: () => _onSelect(index),
          child: Container(
            padding: EdgeInsets.symmetric(vertical: 20, horizontal: 20),
            decoration: BoxDecoration(
              border: Border.all(
                color: borderColor,
                width: 2
              )
            ),
            child: Row(
              children: <Widget> [
                Expanded(
                  child: Text(_items[index].toString(),
                    textAlign: TextAlign.left,
                    overflow: TextOverflow.ellipsis,
                  )
                )
              ]
            )
          )
        );
      },
    );
  }
}

非工作版本,将selectedIndex传递给子窗口小部件

import 'package:flutter/material.dart';

class SelectedIndex extends StatefulWidget {
  @override
  State<StatefulWidget> createState() => SelectedIndexState();
}

class SelectedIndexState extends State<SelectedIndex> {
  List<int> _items = List.from([0]);
  int _selectedIndex = -1;

  @override
  Widget build(BuildContext context) {
    return SafeArea(
      child: Column(
        children: <Widget>[
          Row(
            children: <Widget>[
              IconButton(
                icon: Icon(Icons.indeterminate_check_box),
                onPressed: () {
                  setState(() {
                    _items.removeAt(_selectedIndex);
                  });
                }
              ),
              IconButton(
                icon: Icon(Icons.add_box),
                onPressed: () {
                  setState(() {
                    _items.add(_items.length);
                  });
                }
              )
            ]
          ),
          Expanded(
            child: ItemList(
              items: _items,
              selectedIndex: _selectedIndex,
              onSelect: (index) => setState(() {
                _selectedIndex = index;
              })
            )
          )
        ],
      )
    );
  }
}

class ItemList extends StatefulWidget {
  final List<int> _items;
  final int _selectedIndex;
  final Function _onSelect;

  ItemList({items, selectedIndex, onSelect}) :
    _items = items,
    _selectedIndex = selectedIndex,
    _onSelect = onSelect;

  @override
  State<StatefulWidget> createState() => ItemListState(
    items: _items,
    selectedIndex: _selectedIndex,
    onSelect: _onSelect
  );
}

class ItemListState extends State<ItemList> {
  final List<int> _items;
  final int _selectedIndex;
  final Function _onSelect;


  ItemListState({items, selectedIndex, onSelect}) :
    _items = items,
    _selectedIndex = selectedIndex,
    _onSelect = onSelect;

  @override
  Widget build(BuildContext context) {
    return ListView.builder(
      itemCount: _items.length,
      itemBuilder: (BuildContext context, int index) {
        // I used a withOpacity(0) below to make the border transparent
        // The background colors of the ListView isn't quite white
        final Color borderColor = _selectedIndex == index ?
          Theme.of(context).primaryColor : Colors.white.withOpacity(0);
        return GestureDetector(
          onTap: () => _onSelect(index),
          child: Container(
            padding: EdgeInsets.symmetric(vertical: 20, horizontal: 20),
            decoration: BoxDecoration(
              border: Border.all(
                color: borderColor,
                width: 2
              )
            ),
            child: Row(
              children: <Widget> [
                Expanded(
                  child: Text(_items[index].toString(),
                    textAlign: TextAlign.left,
                    overflow: TextOverflow.ellipsis,
                  )
                )
              ]
            )
          )
        );
      },
    );
  }
}

我了解在第一个版本中,传递给子窗口小部件的功能永远不会改变。这就是为什么我没有问题显示选择哪个项目的原因。有人能够帮助我理解第二个示例所缺少的内容。为什么flutter不更新子窗口小部件中的selectedIndex?使用调试器,我可以看到在更新selectedIndex时重建了子窗口小部件,但是子窗口小部件中的值保持不变。我来自React,在这里我需要做的就是更新道具。这不是Flutter的工作原理吗?

0 个答案:

没有答案