import 'package:flutter/cupertino.dart'; import 'package:flutter/material.dart'; class AnimatedSwitcherWidget extends StatefulWidget { final SwitcherController controller; final Duration duration; const AnimatedSwitcherWidget({ super.key, required this.controller, this.duration = const Duration(milliseconds: 1500), }); @override State createState() => _AnimatedSwitcherWidgetState(); } class _AnimatedSwitcherWidgetState extends State { Widget? _currentWidget; @override void initState() { super.initState(); // 注册更新回调 widget.controller._registerOnUpdate(() => setState(() { _currentWidget = widget.controller._currentWidget; })); } @override Widget build(BuildContext context) { return ClipRRect( child: AnimatedSwitcher( duration: widget.duration, transitionBuilder: (Widget child, Animation animation) { return SlideTransitionX( direction: AxisDirection.down, position: animation, child: child, ); }, child: Center(key: ValueKey(_currentWidget), child: _currentWidget), ), ); } } class SwitcherController { // 保存当前组件和回调函数 Widget? _currentWidget; VoidCallback? _onUpdate; // 更新组件并触发回调 void updateWidget(Widget newWidget) { _currentWidget = newWidget; _onUpdate?.call(); } // 注册更新回调(供State内部调用) void _registerOnUpdate(VoidCallback onUpdate) { _onUpdate = onUpdate; } } class SlideTransitionX extends AnimatedWidget { SlideTransitionX({ super.key, required Animation position, this.transformHitTests = true, this.direction = AxisDirection.down, required this.child, }) : super(listenable: position) { switch (direction) { case AxisDirection.up: _tween = Tween(begin: const Offset(0, 1), end: const Offset(0, 0)); break; case AxisDirection.right: _tween = Tween(begin: const Offset(-1, 0), end: const Offset(0, 0)); break; case AxisDirection.down: _tween = Tween(begin: const Offset(0, -1), end: const Offset(0, 0)); break; case AxisDirection.left: _tween = Tween(begin: const Offset(1, 0), end: const Offset(0, 0)); break; } } final bool transformHitTests; final Widget child; final AxisDirection direction; late final Tween _tween; @override Widget build(BuildContext context) { final position = listenable as Animation; Offset offset = _tween.evaluate(position); if (position.status == AnimationStatus.reverse) { switch (direction) { case AxisDirection.up: offset = Offset(offset.dx, -offset.dy); break; case AxisDirection.right: offset = Offset(-offset.dx, offset.dy); break; case AxisDirection.down: offset = Offset(offset.dx, -offset.dy); break; case AxisDirection.left: offset = Offset(-offset.dx, offset.dy); break; } } return FractionalTranslation( translation: offset, transformHitTests: transformHitTests, child: child, ); } }