¡Acostúmbrate a escribir juntos! Este es el primer día de mi participación en el "Nuggets Daily New Plan · April Update Challenge", haz clic para ver los detalles del evento .
Para buscar una mejor experiencia de usuario, a veces necesitamos un control que lata como un latido del corazón para atraer la atención del usuario. Este es un pequeño requisito de optimización, pero en Flutter, la animación de dos piezas apesta como una envoltura de pies. Es larga, por lo que necesita encapsular un AnimatedWidget para liberar la productividad.
implementar animación
混入 SingleTickerProviderStateMixin
Al crear un AnimationController, debe pasar un vsync
parámetro que, cuando esté presente vsync
, evitará que la IU animada consuma recursos innecesarios cuando no esté en la pantalla actual. Mezclando en SingleTickerProviderStateMixin.
class _MyHomePageState extends State<MyHomePage> with SingleTickerProviderStateMixin{}
复制代码
Crear animación
Cree un controlador de animación con un intervalo de casi un segundo:
late final AnimationController animController;
@override
void initState() {
super.initState();
animController = AnimationController(
duration: const Duration(milliseconds: 800),
vsync: this,
);
}
复制代码
La animación de los latidos del corazón es de pequeño a grande y luego a pequeño, por lo que necesita una animación que cambie el tamaño del valor:
late final Animation<double> animation;
@override
void initState() {
super.initState();
animController = AnimationController(
duration: const Duration(milliseconds: 800),
vsync: this,
);
animation = Tween<double>(
begin: 0.9,
end: 1.05,
);
}
复制代码
El latido del corazón es ininterrumpido, por lo que debe monitorear la animación para reanudarla cuando finalice y luego continuar para iniciar la animación:
animation = Tween<double>(
begin: 0.9,
end: 1.05,
).animate(animController)
..addListener(() {
setState(() {});
})
..addStatusListener((status) {
if (status == AnimationStatus.completed) {
animController.reverse();
} else if (status == AnimationStatus.dismissed) {
animController.forward();
}
});
复制代码
Utilice los controles de zoom:
Transform.scale(
scale: animation.value,
child: const FlutterLogo(
size: 80,
),
),
复制代码
Para el efecto de salto, resalte la animación de salto y acorte el tiempo de retracción:
animController = AnimationController(
reverseDuration: const Duration(milliseconds: 700),
duration: const Duration(milliseconds: 800),
vsync: this,
);
复制代码
Por último, no te olvides de liberar recursos:
@override
void dispose() {
animController.dispose();
super.dispose();
}
复制代码
Extraer en pequeños componentes
Para usar una animación similar cada vez que solo necesite importarla, debe separar los componentes de animación y visualización. Cree uno nuevo BounceWidget
, incluya animación y luego pase los componentes de la interfaz de usuario:
class BounceWidget extends StatefulWidget {
final Widget child;
const BounceWidget({
Key? key,
required this.child,
}) : super(key: key);
@override
State<BounceWidget> createState() => _BounceWidgetState();
}
复制代码
Continúe implementando la animación:
class _BounceWidgetState extends State<BounceWidget>
with SingleTickerProviderStateMixin {
late Animation<double> animation;
late AnimationController animController;
@override
void initState() {
super.initState();
animController = AnimationController(
reverseDuration: const Duration(milliseconds: 700),
duration: const Duration(milliseconds: 800),
vsync: this,
);
animation = Tween<double>(
begin: 0.9,
end: 1.05,
).animate(animController)
..addListener(() {
setState(() {});
})
..addStatusListener((status) {
if (status == AnimationStatus.completed) {
animController.reverse();
} else if (status == AnimationStatus.dismissed) {
animController.forward();
}
});
animController.forward();
}
@override
Widget build(BuildContext context) {
return Transform.scale(
scale: animation.value,
child: widget.child,
);
}
@override
void dispose() {
animController.dispose();
super.dispose();
}
}
复制代码
Para importar animación:
Center(
child: BounceWidget(
child: FlutterLogo(
size: 80,
),
),
复制代码
Código completo:
void main() {
runApp(const MyApp());
}
class MyApp extends StatelessWidget {
const MyApp({Key? key}) : super(key: key);
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: const MyHomePage(title: 'Flutter Demo Home Page'),
);
}
}
class MyHomePage extends StatefulWidget {
const MyHomePage({Key? key, required this.title}) : super(key: key);
final String title;
@override
State<MyHomePage> createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text(widget.title),
),
body: Padding(
padding: const EdgeInsets.only(top: 80, left: 16),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: const <Widget>[
Text(
"心动的",
style: TextStyle(
fontSize: 28,
color: Colors.black,
),
),
Text(
"感觉",
style: TextStyle(
fontSize: 48,
color: Colors.black,
),
),
Center(
child: BounceWidget(
child: FlutterLogo(
size: 80,
),
),
),
],
),
),
);
}
}
复制代码