Reputation: 141
I want switch status with animation in CustomScrollView
, but it throw error.
class SliverAnimatedSwitcher extends StatefulWidget {
final state;
const SliverAnimatedSwitcher({Key key, this.state}) : super(key: key);
@override
_SliverAnimatedSwitcherState createState() => _SliverAnimatedSwitcherState();
}
class _SliverAnimatedSwitcherState extends State<SliverAnimatedSwitcher> {
@override
Widget build(BuildContext context) {
return Scaffold(
body: CustomScrollView(
slivers: <Widget>[
SliverAppBar(
title: Text('SliverAnimatedSwitcher'),
),
_buildContent(),
],
),
);
}
get state => widget.state;
Widget _buildContent() {
var content;
if (state.isNotEmpty == true) {
content = SliverList(
delegate: SliverChildBuilderDelegate(
(context, index) {
var item = state.items[index];
return ListTile(
title: Text(item.title),
);
},
childCount: state.items.length,
),
);
} else if (state.isError) {
content = SliverFillRemaining(
key: Key('error'),
child: Container(alignment: Alignment.center, child: Text('Error')),
);
} else if (state.isLoading) {
content = SliverFillRemaining(
key: Key('loading'),
child: Container(alignment: Alignment.center, child: Text('Loading')),
);
} else {
content = SliverFillRemaining(
key: Key('empty'),
child: Container(alignment: Alignment.center, child: Text('Empty')),
);
}
return AnimatedSwitcher(
duration: Duration(milliseconds: 300),
child: content,
);
}
}
Upvotes: 13
Views: 3467
Reputation: 1
I created the following class the resolve the same issue for my personal project. It should work here, although it can definitely be improved. The main issue is that Flutter does not have a SliverStack
, so my class is more of a workaround. Just wrap each sliver widget with the following class and provide opposing booleans for each:
import 'package:flutter/widgets.dart';
/// A sliver that animates its visibility.
class SliverAnimatedVisibility extends StatelessWidget {
/// Creates a new [SliverAnimatedVisibility].
const SliverAnimatedVisibility({
super.key,
this.curve = Curves.fastOutSlowIn,
this.duration = const Duration(milliseconds: 350),
required this.visible,
required this.sliver,
});
/// The curve to use for the animation.
final Curve curve;
/// The amount of time occupied by the animation.
final Duration duration;
/// Whether the child is visible.
final bool visible;
/// The sliver to display.
final Widget sliver;
@override
Widget build(BuildContext context) {
return SliverAnimatedOpacity(
opacity: visible ? 1 : 0,
curve: curve,
duration: duration,
sliver: SliverVisibility(
visible: visible,
sliver: sliver,
),
);
}
}
I wrote this in 2-3 minutes, so feel free to update the code as you need! 😄
Upvotes: 0
Reputation: 17616
There's a sliver_tools package on pub.dev that has a SliverAnimatedSwitcher. You'd use it like this:
SliverAnimatedSwitcher(
duration: kThemeAnimationDuration,
child: content,
)
Upvotes: 7
Reputation: 4499
It is because sliver widget is not capable with Stack
which is using as layout builder inside AnimatedSwitcher
.
I found a temporary solution. Though the result is not equal to the original one (only show the last widget in the result), but I think it is acceptable for me now with such little effort.
SliverAnimatedSwitcher
exact the same code as AnimatedSwitcher
hereStack
part to return the currentChild
only (defaultLayoutBuilder)FadeTransition
to SliverFadeTransition
(defaultTransitionBuilder).
static Widget defaultLayoutBuilder(Widget currentChild, List<Widget> previousChildren) {
return currentChild;
}
.
static Widget defaultTransitionBuilder(Widget child, Animation<double> animation) {
return SliverFadeTransition(
opacity: animation,
sliver: child,
);
}
If someone can find a way to Stack Sliver widgets above each other, the result may be more perfect.
Upvotes: 3