When nested CustomScrollView's shrink wrap set true, i can't collapse child slivers.
How to scroll both customScrollViews and make child customScrollView collapsable into minimum height.
Here is live demo
My final goal is to make stack card list view with scrolling animation
Any other solutions ? or got a way to solve this issue ?
Give me some advise masters :)
class AnimationTest extends StatefulWidget {
@override
_AnimationTestState createState() => _AnimationTestState();
}
class _AnimationTestState extends State<AnimationTest>
with WidgetsBindingObserver {
@override
void initState() {
WidgetsBinding.instance.addObserver(this);
super.initState();
}
@override
void dispose() {
WidgetsBinding.instance.removeObserver(this);
super.dispose();
}
@override
void didChangeAppLifecycleState(AppLifecycleState state) {
print(state.toString());
}
@override
Widget build(BuildContext context) {
const double goldenRatio = 1.618;
final Size displaySize = MediaQuery.of(context).size;
final double minCardHeight = 24;
final double maxCardHeight = 80;
final List<Color> colors = Colors.primaries;
List<Color> _colors = List();
_colors.addAll(colors);
_colors.addAll(colors);
print(_colors.length);
return Scaffold(
body: Container(
color: Colors.white,
padding: EdgeInsets.only(top: 40),
alignment: AlignmentDirectional.center,
child: CustomScrollView(
slivers: <Widget>[
SliverList(
delegate: SliverChildListDelegate([
Column(
crossAxisAlignment: CrossAxisAlignment.center,
children: <Widget>[
CreditCard(),
Container(
width: displaySize.width * 0.85,
height: minCardHeight * _colors.length,
alignment: AlignmentDirectional.bottomCenter,
margin: EdgeInsets.all(0),
padding: EdgeInsets.all(0),
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(8),
color: Colors.white,
),
child: StackedList(
minCardHeight: minCardHeight,
maxCardHeight: maxCardHeight,
colors: _colors,
),
)
],
),
]),
)
],
),
),
);
}
}
class StackedList extends StatefulWidget {
final double minCardHeight;
final double maxCardHeight;
final List<Color> colors;
StackedList({
Key key,
this.colors,
this.maxCardHeight,
this.minCardHeight,
}) : super(key: key);
@override
_StackedListState createState() => _StackedListState();
}
class _StackedListState extends State<StackedList> {
@override
Widget build(BuildContext context) {
return CustomScrollView(
physics: AlwaysScrollableScrollPhysics(),
shrinkWrap: true,
slivers: <Widget>[
...widget.colors
.map(
(color) => StackedListChild(
minHeight: widget.minCardHeight,
maxHeight: widget.maxCardHeight,
floating: false,
pinned: true,
child: getCard(
cardId: widget.colors.indexOf(color).toString(),
color: color,
),
),
)
.toList(),
SliverToBoxAdapter(
child: Container(
height: MediaQuery.of(context).size.height,
alignment: Alignment.center,
))
],
);
}
Widget getCard({String cardId, Color color}) {
const double cardWidth = 300;
const double cardHeight = 370;
return Hero(
tag: cardId,
child: Material(
elevation: 3,
color: Colors.white,
child: InkWell(
onTap: () => navigateToCardDetail(cardId: cardId, color: color),
child: Container(
width: cardWidth,
height: cardHeight,
color: color,
// decoration: BoxDecoration(
// borderRadius: BorderRadius.only(
// topLeft: Radius.circular(8),
// topRight: Radius.circular(8),
// ),
// color: color,
// ),
),
),
),
);
}
navigateToCardDetail({String cardId, Color color}) {
var route = PageRouteBuilder(
pageBuilder: (context, animation, secondAnimation) =>
SecondPage(cardId: cardId, color: color),
barrierDismissible: true,
transitionDuration: const Duration(milliseconds: 300),
transitionsBuilder: (context, animation, secondaryAnimation, child) {
// var begin = Offset(0.0, 1.0);
// var end = Offset.zero;
// var curve = Curves.fastOutSlowIn;
// var tween =
// Tween(begin: begin, end: end).chain(CurveTween(curve: curve));
return FadeTransition(
//opacity: animation,
//position: animation.drive(tween),
opacity: animation,
child: child,
);
},
);
Navigator.of(context).push(route);
}
}
class StackedListChild extends StatelessWidget {
final double minHeight;
final double maxHeight;
final bool pinned;
final bool floating;
final Widget child;
SliverPersistentHeaderDelegate get _delegate => _StackedListDelegate(
minHeight: minHeight, maxHeight: maxHeight, child: child);
const StackedListChild({
Key key,
@required this.minHeight,
@required this.maxHeight,
@required this.child,
this.pinned = false,
this.floating = false,
}) : assert(child != null),
assert(minHeight != null),
assert(maxHeight != null),
assert(pinned != null),
assert(floating != null),
super(key: key);
@override
Widget build(BuildContext context) => SliverPersistentHeader(
key: key, pinned: pinned, floating: floating, delegate: _delegate);
}
class _StackedListDelegate extends SliverPersistentHeaderDelegate {
final double minHeight;
final double maxHeight;
final Widget child;
_StackedListDelegate({
@required this.minHeight,
@required this.maxHeight,
@required this.child,
});
@override
double get minExtent => minHeight;
@override
double get maxExtent => math.max(maxHeight, minHeight);
@override
Widget build(
BuildContext context, double shrinkOffset, bool overlapsContent) {
return new SizedBox.expand(child: child);
}
@override
bool shouldRebuild(_StackedListDelegate oldDelegate) {
return maxHeight != oldDelegate.maxHeight ||
minHeight != oldDelegate.minHeight ||
child != oldDelegate.child;
}
}