问题是:当我单击其中一个 CharBarButtons 小部件时,所有其他 CharBarButtons 也会被重建,是否有一种方法可以避免这种情况,并在使用 StateNotifier 保存列表时单独进行重建(整数是按钮的位置)
CharBarButtons :(这里我根据 isTapped 的布尔值更改 CharBarButtons 的装饰)
class CharBarButtons extends HookWidget {
CharBarButtons({required this.index});
final int index;
@override
Widget build(BuildContext context) {
final isTapped = useProvider(IndexStackProvider).contains(index);
final _randomBar = useProvider(randomBarProvider);
final usableWidth = MediaQuery.of(context).size.width -
(MediaQuery.of(context).padding.left +
MediaQuery.of(context).padding.right);
final usableHeight = MediaQuery.of(context).size.height -
(MediaQuery.of(context).padding.bottom +
MediaQuery.of(context).padding.top);
return InkWell(
onTap: () {
if (isTapped == false) {
context.read(IndexStackProvider.notifier).append(index);
}
},
child: AnimatedContainer(
curve: Curves.easeOutExpo,
duration: Duration(milliseconds: 125),
child: Center(
child: Center(
child: Opacity(
opacity: isTapped == false ? 1 : 0.5,
child: Text('${_randomBar[index]}',
style: TextStyle(
color: Colors.black87,
fontWeight: FontWeight.bold,
fontSize: usableHeight * 0.03)),
))),
width: usableWidth * 0.12,
height: usableWidth * 0.12,
decoration: isTapped == false
? BoxDecoration(
color: const Color.fromRGBO(255, 227, 212, 1),
border: Border.all(
color: Colors.black.withOpacity(0.6), width: 2),
borderRadius: BorderRadius.circular(usableWidth * 0.02),
shape: BoxShape.rectangle,
)
: BoxDecoration(
color: Color.fromRGBO(199, 177, 165, 1),
border: Border.all(
color: Colors.black.withOpacity(0.3), width: 2),
borderRadius: BorderRadius.circular(usableWidth * 0.02),
shape: BoxShape.rectangle,
)));
}
}
CharBarButtons 的祖先:CharBar 小部件是一个简单的小部件,决定应创建多少个 CharBarButton。
class CharBar extends HookWidget {
const CharBar({Key? key}) : super(key: key);
@override
Widget build(BuildContext context) {
final usableWidth = MediaQuery.of(context).size.width -
(MediaQuery.of(context).padding.left +
MediaQuery.of(context).padding.right);
final usableHeight = MediaQuery.of(context).size.height -
(MediaQuery.of(context).padding.bottom +
MediaQuery.of(context).padding.top);
final _randomChars = useProvider(randomBarProvider);
return Container(
height: usableWidth * 0.24,
width: usableWidth,
child: _randomChars.length <= 6
? Row(mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [
for (var i = 0; i < _randomChars.length; i++)
CharBarButtons(index: i)
])
: Column(children: [
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
for (var i = 0; i < _randomChars.length ~/ 2; i++)
CharBarButtons(index: i)
],
),
SizedBox(height: usableHeight * 0.05),
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
for (var i = _randomChars.length ~/ 2;
i < _randomChars.length;
i++)
CharBarButtons(index: i)
],
)
]),
);
}
}
这是 StateNotifier :
class IndexStackState extends StateNotifier<List<int>> {
IndexStackState() : super([]);
void append(int index) {
state = [...state, index];
}
void delete() {
state = [...state.sublist(0, state.length - 1)];
}
void reset() {
state = [];
}
}
这是提供者:
final IndexStackProvider =
StateNotifierProvider.autoDispose<IndexStackState, List<int>>(
(ref) => IndexStackState());
注意:CharBar(祖先)没有任何不必要的重建或另一个祖先。只有 CharBarButtons 进行了不必要的重建。
注 2:我知道 contains() 方法也很昂贵,但我将列表限制为最多 12 个整数元素。所以我认为这应该不是什么太大的问题。
注 3:问题是由于这行代码(代码的第一段)引起的,并且当状态更新时它会重建所有 CharBarButton,我无法以索引方式监听。我在这里监听整个列表。
final isTapped = useProvider(IndexStackProvider).contains(index);
注 4:实际问题是,我们是否可以将重建限制为索引方式,而不是监听整个列表状态