Flutter翻转动画
import 'dart:math';
import 'package:flutter/material.dart';
void main() {
runApp(const MyApp());
}
class MyApp extends StatelessWidget {
const MyApp({super.key});
// This widget is the root of your application.
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
theme: ThemeData(
primarySwatch: Colors.blue,
visualDensity: VisualDensity.adaptivePlatformDensity,
),
home: const MyHomePage(
title: 'Flip Animation Example',
key: ValueKey('home'),
),
);
}
}
class MyHomePage extends StatefulWidget {
const MyHomePage({required Key key, required this.title}) : super(key: key);
final String title;
_MyHomePageState createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
late bool _showFrontSide;
late bool _flipXAxis;
void initState() {
super.initState();
_showFrontSide = true;
_flipXAxis = true;
}
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text(widget.title),
centerTitle: true,
actions: [
IconButton(
icon: RotatedBox(
quarterTurns: _flipXAxis ? 0 : 1,
child: const Icon(Icons.flip),
),
onPressed: _changeRotationAxis,
),
],
),
body: DefaultTextStyle(
style: const TextStyle(color: Colors.white),
textAlign: TextAlign.center,
child: Center(
child: Container(
constraints: BoxConstraints.tight(const Size.square(200.0)),
child: _buildFlipAnimation(),
),
),
),
);
}
void _changeRotationAxis() {
setState(() {
_flipXAxis = !_flipXAxis;
});
}
void _switchCard() {
setState(() {
_showFrontSide = !_showFrontSide;
});
}
Widget _buildFlipAnimation() {
return GestureDetector(
onTap: _switchCard,
child: AnimatedSwitcher(
duration: const Duration(milliseconds: 800),
transitionBuilder: __transitionBuilder,
layoutBuilder: (widget, list) => Stack(children: [widget!, ...list]),
switchInCurve: Curves.easeInBack,
switchOutCurve: Curves.easeInBack.flipped,
child: _showFrontSide ? _buildFront() : _buildRear(),
),
);
}
Widget __transitionBuilder(Widget widget, Animation<double> animation) {
final rotateAnim = Tween(begin: pi, end: 0.0).animate(animation);
return AnimatedBuilder(
animation: rotateAnim,
child: widget,
builder: (context, widget) {
final isUnder = (ValueKey(_showFrontSide) != widget?.key);
var tilt = ((animation.value - 0.5).abs() - 0.5) * 0.003;
tilt *= isUnder ? -1.0 : 1.0;
final value =
isUnder ? min(rotateAnim.value, pi / 2) : rotateAnim.value;
return Transform(
transform: _flipXAxis
? (Matrix4.rotationY(value)..setEntry(3, 0, tilt))
: (Matrix4.rotationX(value)..setEntry(3, 1, tilt)),
alignment: Alignment.center,
child: widget,
);
},
);
}
Widget _buildFront() {
return __buildLayout(
key: const ValueKey(true),
backgroundColor: Colors.blue,
faceName: "Front",
child: const Padding(
padding: EdgeInsets.all(32.0),
child: ColorFiltered(
colorFilter: ColorFilter.mode(Colors.white, BlendMode.srcATop),
child: FlutterLogo(),
),
),
);
}
Widget _buildRear() {
return __buildLayout(
key: const ValueKey(false),
backgroundColor: Colors.blue.shade700,
faceName: "Rear",
child: const Padding(
padding: EdgeInsets.all(20.0),
child: ColorFiltered(
colorFilter: ColorFilter.mode(Colors.white, BlendMode.srcATop),
child:
Center(child: Text("Flutter", style: TextStyle(fontSize: 50.0))),
),
),
);
}
Widget __buildLayout(
{required Key key,
required Widget child,
required String faceName,
required Color backgroundColor}) {
return Container(
key: key,
decoration: BoxDecoration(
shape: BoxShape.rectangle,
borderRadius: BorderRadius.circular(20.0),
color: backgroundColor,
),
child: Center(
child: Text(faceName.substring(0, 1),
style: const TextStyle(fontSize: 80.0)),
),
);
}
}
可以直接复制到 https://dartpad.dev/ 中浏览效果