我有这个简单的有状态小部件:
class SomeListWidget extends StatefulWidget {
const SomeListWidget({super.key});
@override
State<SomeListWidget> createState() => _SomeListWidgetState();
}
class _SomeListWidgetState extends State<SomeListWidget> {
List<Color> colors = [
Colors.red,
Colors.green,
];
@override
Widget build(BuildContext context) {
return Scaffold(
body: Column(
children: [
Expanded(
child: ListView.builder(
itemCount: colors.length,
reverse: true,
itemBuilder: (context, index) {
return ColorTransitionBox(
targetColor: colors[index],
);
},
),
),
ElevatedButton(
onPressed: () {
setState(() {
final rnd = Random();
final color = Color.fromARGB(
255, rnd.nextInt(256), rnd.nextInt(256), rnd.nextInt(256));
colors.insert(0, color);
});
},
child: Text('Add color'),
),
],
),
);
}
}
ColorTransitionBox 小部件将其颜色从白色线性更改为目标颜色:
class ColorTransitionBox extends StatefulWidget {
final Color targetColor;
const ColorTransitionBox({Key? key, required this.targetColor})
: super(key: key);
@override
State<ColorTransitionBox> createState() => _ColorTransitionBoxState();
}
class _ColorTransitionBoxState extends State<ColorTransitionBox> {
Color _currentColor = Colors.white;
@override
void initState() {
super.initState();
// Start the color transition after the first frame is rendered
WidgetsBinding.instance.addPostFrameCallback((_) {
setState(() {
_currentColor = widget.targetColor;
});
});
}
@override
Widget build(BuildContext context) {
return AnimatedContainer(
duration: const Duration(seconds: 1),
curve: Curves.linear, // Linear animation
color: _currentColor,
width: 100, // Example width
height: 100, // Example height
child: Center(
child: Text(
'Color Box',
style: TextStyle(
color: _currentColor == Colors.white ? Colors.black : Colors.white,
),
),
),
);
}
}
当我单击“添加颜色”时,我希望底部出现一个新框,在 1 秒内将颜色从白色线性更改为随机。但是当我单击时,顶部会出现一个框,其颜色始终与列表中最后一项的颜色相匹配(在本例中为绿色)。我需要反转 ListView 并且新的小部件出现在底部。
我尝试使用UniqueKey
Expanded(
child: ListView.builder(
itemCount: colors.length,
reverse: true,
itemBuilder: (context, index) {
return ColorTransitionBox(
key: UniqueKey(),
targetColor: colors[index],
);
},
),
),
它有效,但现在当我添加一个新元素时,所有其他元素再次开始转换 我也使用 ValueKey(colors[index]),但结果是一样的。
这可以解决问题:
@override
void didUpdateWidget(covariant ColorTransitionBox oldWidget) {
super.didUpdateWidget(oldWidget);
if (widget.targetColor != oldWidget.targetColor) {
currentColor = widget.targetColor;
} // to sync the newly added dynamic color
}
这是针对您的问题的重构代码片段解决方案:
import 'dart:math';
import 'package:flutter/material.dart';
class SomeListWidget extends StatefulWidget {
const SomeListWidget({super.key});
@override
State<SomeListWidget> createState() => _SomeListWidgetState();
}
class _SomeListWidgetState extends State<SomeListWidget> {
List<Color> colors = [
Colors.red,
Colors.green,
];
@override
Widget build(BuildContext context) {
return Scaffold(
body: Column(
children: [
Expanded(
child: ListView.builder(
itemCount: colors.length,
reverse: true,
itemBuilder: (context, index) {
return ColorTransitionBox(
targetColor: colors[index],
);
},
),
),
ElevatedButton(
onPressed: () {
setState(() {
final rnd = Random();
final color = Color.fromARGB(
255, rnd.nextInt(256), rnd.nextInt(256), rnd.nextInt(256));
colors.insert(0, color);
});
},
child: Text('Add color'),
),
],
),
);
}
}
class ColorTransitionBox extends StatefulWidget {
final Color? targetColor;
const ColorTransitionBox({super.key, required this.targetColor});
@override
State<ColorTransitionBox> createState() => _ColorTransitionBoxState();
}
class _ColorTransitionBoxState extends State<ColorTransitionBox> {
Color? currentColor;
@override
void initState() {
super.initState();
// Start the color transition after the first frame is rendered
WidgetsBinding.instance.addPostFrameCallback((_) {
if (mounted) {
setState(() {
currentColor = widget.targetColor;
});
}
}); // still needed this to initialize the color from the parent widget
}
@override
void didUpdateWidget(covariant ColorTransitionBox oldWidget) {
super.didUpdateWidget(oldWidget);
if (widget.targetColor != oldWidget.targetColor) {
currentColor = widget.targetColor;
} // to sync the newly added dynamic color
}
@override
Widget build(BuildContext context) {
return AnimatedContainer(
duration: const Duration(seconds: 1),
curve: Curves.linear, // Linear animation
color: currentColor,
width: 100, // Example width
height: 100, // Example height
child: Center(
child: Text(
'Color Box',
style: TextStyle(
color: currentColor == Colors.white ? Colors.black : Colors.white,
),
),
),
);
}
}
希望对你有帮助!