My app currently looks like this:
And the here's the code behind it:
import 'package:flutter/material.dart';
import 'package:flutter/painting.dart';
import 'package:flutter/services.dart';
void main() {
runApp(const MyApp());
}
class MyApp extends StatelessWidget {
const MyApp({Key? key}) : super(key: key);
// This widget is the root of your application.
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
theme: ThemeData(
primarySwatch: Colors.lightBlue),
home: const MyHomePage(),
);
}
}
class MyHomePage extends StatefulWidget {
const MyHomePage({Key? key}) : super(key: key);
@override
State<MyHomePage> createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
@override
Widget build(BuildContext context) {
return Scaffold(
body: SafeArea(
child: Center(
child: Column(children: [
Card(
shape: const RoundedRectangleBorder(
borderRadius: BorderRadius.only(
bottomLeft: Radius.circular(24),
bottomRight: Radius.circular(24))),
elevation: 30,
child: Padding(
padding: EdgeInsets.only(top: 120, right: 15, bottom: 20, left: 15),
child: Column(
crossAxisAlignment: CrossAxisAlignment.center,
children: [
TextField(
controller: TextEditingController(text: '12121 1212'),
keyboardType: TextInputType.none,
textAlign: TextAlign.end,
style: TextStyle().copyWith(fontSize: 70),
decoration: InputDecoration(border: InputBorder.none),
),
Align(
alignment: Alignment.centerRight,
child: Text(
'Result',
style: TextStyle().copyWith(fontSize: 36),
),
),
Container(
height: 6,
width: 25,
decoration: BoxDecoration(
color: Colors.black,
borderRadius: BorderRadius.all(Radius.circular(14))),
)
],
)),
),
Expanded(child: Container())
]))));
}
}
Now, I want to scroll down the this card to reveal a list above it,something like this: https://youtu.be/qZtGjd_-KwI
I think it could be done with CustomScrollView, but as a novices CustomScrollView and Slivers are a bit complex for me to understand. A little help regrading how to go about this would be appreciated.
CodePudding user response:
I think you want a CustomScrollView
. This will get you close (but won't collapse the main body as in your video example). Note if you provide a hasScrollBody
to true then you're body will shrink in response but it'll then overflow. Even a ConstrainedBox with minimum height didn't work for me so that shrinking part is really the hardest part.
class MyHomePage extends StatelessWidget {
MyHomePage({Key? key}) : super(key: key);
final centerKey = GlobalKey();
@override
Widget build(BuildContext context) {
return Scaffold(
body: CustomScrollView(
center: centerKey,
slivers: [
const SliverAppBar(title: Text('The real title')),
SliverList(
delegate: SliverChildListDelegate.fixed(
[
Container(
color: Colors.pink,
child: Column(
mainAxisSize: MainAxisSize.max,
children: [
Container(
width: double.infinity,
height: 200.0,
color: Colors.pink,
),
Container(
width: double.infinity,
height: 200.0,
color: Colors.blue,
),
Container(
width: double.infinity,
height: 200.0,
color: Colors.red,
),
],
),
),
],
),
),
SliverAppBar(
key: centerKey,
expandedHeight: 100.0,
backgroundColor: Colors.transparent,
flexibleSpace: const Card(
margin: EdgeInsets.zero,
elevation: 14.0,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.vertical(
bottom: Radius.circular(32.0),
),
),
child: SizedBox.expand(),
),
),
SliverFillRemaining(
hasScrollBody: false,
child: SafeArea(
top: false,
child: Padding(
padding: const EdgeInsets.symmetric(horizontal: 16.0),
child: Column(
mainAxisSize: MainAxisSize.max,
children: List.generate(5, (i) => i).map((i) {
return Expanded(
child: Row(
children: List.generate(4, (i) => i).map((i) {
return const Expanded(
child: Placeholder(),
);
}).toList(),
),
);
}).toList(),
),
),
),
),
],
),
);
}
}
The main part you should concern yourself with is the centerKey
. That tells the CustomScrollView where it should start from. You pass that to both the CustomScrollView
and the SliverAppBar
.
The SliverFillRemaining
will fill what's left of the viewport, which if you're starting at the SliverAppBar
will be about 80%. FillRemaining will take you into the box model (as opposed to the Sliver model) which allows you to just use the space as you regularly would with columns and what not.