尽管有自己的动画控制器,但 Flutter 小部件共享
Flutter widgets sharing despite having their own animation controller
我有一个水平的小部件列表,当用户在小部件上拖动时,这些小部件能够在 X 轴上翻转。 (中间的大硬币)
使用左右箭头,用户可以循环浏览他们拥有的硬币。
但是,如果用户要抛一枚硬币,然后单击以循环到另一枚硬币,即使它是一个完全不同的对象,硬币也会保持抛掷状态。
硬币:
class Coin extends StatefulWidget {
final Image frontImage = const Image(image: AssetImage("assets/logo.png"));
final Image back = const Image(image: AssetImage("assets/logoback.png"));
const Coin({Key? key}) : super(key: key);
@override
_CoinState createState() => _CoinState();
}
class _CoinState extends State<Coin>
with SingleTickerProviderStateMixin {
late AnimationController controller;
late Animation<double> animation;
bool isFront = true;
double dragPosition = 0;
@override
void initState() {
super.initState();
controller = AnimationController(
duration: const Duration(milliseconds: 500), vsync: this);
controller.addListener(() {
setState(() {
dragPosition = animation.value;
setImageSide();
});
});
}
@override
void dispose() {
controller.dispose();
super.dispose();
}
@override
Widget build(BuildContext context) {
Stack front = Stack(
alignment: const Alignment(0, 0),
children: [
widget.frontImage,
const Text("1", style: TextStyle(fontSize: 100, color: Colors.white))
],
);
final angle = dragPosition / 180 * math.pi;
final transform = Matrix4.identity()
..setEntry(3, 2, 0.001)
..rotateY(angle);
return GestureDetector(
onHorizontalDragUpdate: (details) => setState(() {
dragPosition -= details.delta.dx;
dragPosition %= 360;
setImageSide();
}),
onHorizontalDragEnd: (details) {
double end = isFront ? (dragPosition > 180 ? 360 : 0) : 180;
animation = Tween<double>(
begin: dragPosition,
end: end,
).animate(controller);
controller.forward(from: 0);
},
child: Transform(
transform: transform,
alignment: Alignment.center,
child: isFront
? front
: Transform(
transform: Matrix4.identity()..rotateY(math.pi),
alignment: Alignment.center,
child: widget.back)),
);
}
void setImageSide() {
if (dragPosition <= 90 || dragPosition >= 270) {
isFront = true;
} else {
isFront = false;
}
}
}
首页:
class _HomePageState extends State<HomePage> {
int _currentIndex = 1;
final List _coins = const [widgets.Coin(), widgets.Coin(), widgets.Coin()];
@override
Widget build(BuildContext context) {
return Scaffold(
// Main homepage contents
body: Center(
child: Column(
// Column Alignment
mainAxisAlignment: MainAxisAlignment.center,
mainAxisSize: MainAxisSize.max,
// Main body of home page
children: [
Text(_currentIndex.toString()),
const Spacer(), // Spacing
// Centered Flip Coin widget
Padding(
padding: const EdgeInsets.only(top: 40, bottom: 40),
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: [
// Back coin button
IconButton(
icon: Icon(Icons.arrow_back_ios, color: Colors.grey[600]),
onPressed: () {
if (_currentIndex != 0) {
setState(() {
_currentIndex--;
});
}}),
_coins[_currentIndex], // Coin widget
// Forward coin button
IconButton(
icon: Icon(Icons.arrow_forward_ios, color: Colors.grey[600]),
onPressed: () {
if (_currentIndex < (_coins.length - 1)) {
setState(() {
_currentIndex++;
});
}})
])),
const Spacer(), // Spacing
// Pushup button widget
const Padding(
padding: EdgeInsets.only(left: 8, right: 8),
child: widgets.PushupButton()),
// Group information widget
const Padding(
padding: EdgeInsets.all(8.0),
child: widgets.GroupInfo(),
),
])),
);
}
}
Github(可能有点旧,主要是文件名不同)
https://github.com/bens-schreiber/pushupapp
我已经通过打印当前索引和对象来确保左右按钮确实在对象之间循环,所以我可以确认它在循环。
如果有人知道为什么会这样,请告诉我。
不确定他们是如何共享 isFront
变量的,但是当我将 isFront
从 CoinState
class 移动到 Coin
class 然后它正确地保存了硬币的方向。
我有一个水平的小部件列表,当用户在小部件上拖动时,这些小部件能够在 X 轴上翻转。 (中间的大硬币)
使用左右箭头,用户可以循环浏览他们拥有的硬币。
但是,如果用户要抛一枚硬币,然后单击以循环到另一枚硬币,即使它是一个完全不同的对象,硬币也会保持抛掷状态。
硬币:
class Coin extends StatefulWidget {
final Image frontImage = const Image(image: AssetImage("assets/logo.png"));
final Image back = const Image(image: AssetImage("assets/logoback.png"));
const Coin({Key? key}) : super(key: key);
@override
_CoinState createState() => _CoinState();
}
class _CoinState extends State<Coin>
with SingleTickerProviderStateMixin {
late AnimationController controller;
late Animation<double> animation;
bool isFront = true;
double dragPosition = 0;
@override
void initState() {
super.initState();
controller = AnimationController(
duration: const Duration(milliseconds: 500), vsync: this);
controller.addListener(() {
setState(() {
dragPosition = animation.value;
setImageSide();
});
});
}
@override
void dispose() {
controller.dispose();
super.dispose();
}
@override
Widget build(BuildContext context) {
Stack front = Stack(
alignment: const Alignment(0, 0),
children: [
widget.frontImage,
const Text("1", style: TextStyle(fontSize: 100, color: Colors.white))
],
);
final angle = dragPosition / 180 * math.pi;
final transform = Matrix4.identity()
..setEntry(3, 2, 0.001)
..rotateY(angle);
return GestureDetector(
onHorizontalDragUpdate: (details) => setState(() {
dragPosition -= details.delta.dx;
dragPosition %= 360;
setImageSide();
}),
onHorizontalDragEnd: (details) {
double end = isFront ? (dragPosition > 180 ? 360 : 0) : 180;
animation = Tween<double>(
begin: dragPosition,
end: end,
).animate(controller);
controller.forward(from: 0);
},
child: Transform(
transform: transform,
alignment: Alignment.center,
child: isFront
? front
: Transform(
transform: Matrix4.identity()..rotateY(math.pi),
alignment: Alignment.center,
child: widget.back)),
);
}
void setImageSide() {
if (dragPosition <= 90 || dragPosition >= 270) {
isFront = true;
} else {
isFront = false;
}
}
}
首页:
class _HomePageState extends State<HomePage> {
int _currentIndex = 1;
final List _coins = const [widgets.Coin(), widgets.Coin(), widgets.Coin()];
@override
Widget build(BuildContext context) {
return Scaffold(
// Main homepage contents
body: Center(
child: Column(
// Column Alignment
mainAxisAlignment: MainAxisAlignment.center,
mainAxisSize: MainAxisSize.max,
// Main body of home page
children: [
Text(_currentIndex.toString()),
const Spacer(), // Spacing
// Centered Flip Coin widget
Padding(
padding: const EdgeInsets.only(top: 40, bottom: 40),
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: [
// Back coin button
IconButton(
icon: Icon(Icons.arrow_back_ios, color: Colors.grey[600]),
onPressed: () {
if (_currentIndex != 0) {
setState(() {
_currentIndex--;
});
}}),
_coins[_currentIndex], // Coin widget
// Forward coin button
IconButton(
icon: Icon(Icons.arrow_forward_ios, color: Colors.grey[600]),
onPressed: () {
if (_currentIndex < (_coins.length - 1)) {
setState(() {
_currentIndex++;
});
}})
])),
const Spacer(), // Spacing
// Pushup button widget
const Padding(
padding: EdgeInsets.only(left: 8, right: 8),
child: widgets.PushupButton()),
// Group information widget
const Padding(
padding: EdgeInsets.all(8.0),
child: widgets.GroupInfo(),
),
])),
);
}
}
Github(可能有点旧,主要是文件名不同) https://github.com/bens-schreiber/pushupapp
我已经通过打印当前索引和对象来确保左右按钮确实在对象之间循环,所以我可以确认它在循环。
如果有人知道为什么会这样,请告诉我。
不确定他们是如何共享 isFront
变量的,但是当我将 isFront
从 CoinState
class 移动到 Coin
class 然后它正确地保存了硬币的方向。