Here's what I want to build but I am able to achieve this
by the following code,
@override
Widget build(BuildContext context) {
return Scaffold(
body: NestedScrollView(
headerSliverBuilder: (BuildContext context, bool innerBoxIsScrolled){
return [
SliverAppBar(
expandedHeight: 120,
floating: false,
pinned: false,
flexibleSpace: Container(
padding: EdgeInsets.all(10),
height: 160,
width: double.infinity,
child: Column(
mainAxisAlignment: MainAxisAlignment.end,
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
Align(
alignment: Alignment.topCenter,
child: Text(
'Hello World',
)),
Padding(
padding: EdgeInsets.only(top: 16),
child: Image.asset(
'assets/images/banner.png',
),
),
],
),
),
),
];
},
body: ListView.builder(),
),
);
}
I have tried SliverAppBar using flexible and expanded, but was not able to achieve.
Update - First element of list is going behind text field. I want to scroll only when the animation is completed
updated answer,
@override
Widget build(BuildContext context) {
return Scaffold(
body: CustomScrollView(
slivers: <Widget>[
TransitionAppBar(
extent: 250,
avatar: Text("Rancho"),
title: Container(
margin: EdgeInsets.symmetric(horizontal: 20.0, vertical: 0),
decoration: BoxDecoration(
color: Colors.grey[200],
borderRadius: BorderRadius.all(Radius.circular(5.0))),
child: Row(children: <Widget>[
Padding(
padding: EdgeInsets.only(left: 20.0, right: 10.0),
child: Icon(Icons.search),
),
Expanded(
child: TextFormField(
keyboardType: TextInputType.text,
textInputAction: TextInputAction.done,
cursorColor: Colors.black,
autofocus: false,
style: TextField_Style,
decoration: InputDecoration(
filled: true,
fillColor: Colors.transparent,
contentPadding:
EdgeInsets.symmetric(vertical: 10, horizontal: 15),
hintText: "Search",
border: InputBorder.none,
disabledBorder: OutlineInputBorder(
borderSide: new BorderSide(color: Colors.transparent),
borderRadius: new BorderRadius.circular(2),
),
focusedBorder: OutlineInputBorder(
borderSide: new BorderSide(color: Colors.transparent),
borderRadius: new BorderRadius.circular(2),
)),
),
)
]),
),
),
SliverList(
delegate: SliverChildBuilderDelegate((context, index) {
return Container(
color: Colors.blue,
child: ListTile(
title: Text("${index}a"),
));
}, childCount: 25))
],
),
);
}
.
class TransitionAppBar extends StatelessWidget {
final Widget avatar;
final Widget title;
final double extent;
TransitionAppBar({this.avatar, this.title, this.extent = 250, Key key}) : super(key: key);
@override
Widget build(BuildContext context) {
return SliverPersistentHeader(
pinned: true,
delegate: _TransitionAppBarDelegate(
avatar: avatar,
title: title,
extent: extent > 200 ? extent : 200
),
);
}
}
class _TransitionAppBarDelegate extends SliverPersistentHeaderDelegate {
final _avatarMarginTween = EdgeInsetsTween(
begin: EdgeInsets.only(bottom: 70, left: 30),
end: EdgeInsets.only(left: 0.0, top: 30.0));
final _avatarAlignTween =
AlignmentTween(begin: Alignment.bottomLeft, end: Alignment.topCenter);
final Widget avatar;
final Widget title;
final double extent;
_TransitionAppBarDelegate({this.avatar, this.title, this.extent = 250})
: assert(avatar != null),
assert(extent == null || extent >= 200),
assert(title != null);
@override
Widget build(
BuildContext context, double shrinkOffset, bool overlapsContent) {
double tempVal = 34 * maxExtent / 100;
final progress = shrinkOffset > tempVal ? 1.0 : shrinkOffset / tempVal;
print("Objechjkf === ${progress} ${shrinkOffset}");
final avatarMargin = _avatarMarginTween.lerp(progress);
final avatarAlign = _avatarAlignTween.lerp(progress);
return Stack(
children: <Widget>[
AnimatedContainer(
duration: Duration(milliseconds: 100),
height: shrinkOffset * 2,
constraints: BoxConstraints(maxHeight: minExtent),
color: Colors.redAccent,
),
Padding(
padding: avatarMargin,
child: Align(
alignment: avatarAlign,
child: avatar
),
),
Padding(
padding: EdgeInsets.only(bottom: 10),
child: Align(
alignment: Alignment.bottomCenter,
child: title,
),
)
],
);
}
@override
double get maxExtent => extent;
@override
double get minExtent => (maxExtent * 68) / 100;
@override
bool shouldRebuild(_TransitionAppBarDelegate oldDelegate) {
return avatar != oldDelegate.avatar || title != oldDelegate.title;
}
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With