Reputation: 79
Since i am new to flutter i want the complete implementation of this animation.
Upvotes: 2
Views: 2116
Reputation: 1147
This is exact implementation of this AppBar:
class TransitionAppBar extends StatelessWidget {
TransitionAppBar({
required this.avatar,
required this.title,
this.extent = 250,
Key? key,
}) : super(key: key);
final Widget avatar;
final double extent;
final String title;
@override
Widget build(BuildContext context) {
return SliverPersistentHeader(
pinned: true,
delegate: _TransitionAppBarDelegate(
avatar: avatar,
title: title,
extent: extent > 200 ? extent : 200,
),
);
}
}
class _TransitionAppBarDelegate extends SliverPersistentHeaderDelegate {
_TransitionAppBarDelegate({required this.avatar, required this.title, this.extent = 250})
: assert(extent >= 200, '');
final Widget avatar;
final double extent;
final String title;
final _avatarAlignTween = AlignmentTween(begin: Alignment.bottomCenter, end: Alignment.topLeft);
final _avatarMarginTween = EdgeInsetsTween(
end: EdgeInsets.only(left: 14, top: 36),
);
final _iconAlignTween = AlignmentTween(begin: Alignment.bottomRight, end: Alignment.topRight);
final _titleMarginTween = EdgeInsetsTween(
begin: EdgeInsets.only(bottom: 20),
end: EdgeInsets.only(left: 64, top: 45),
);
@override
double get maxExtent => extent;
@override
double get minExtent => 80;
@override
bool shouldRebuild(_TransitionAppBarDelegate oldDelegate) {
return avatar != oldDelegate.avatar || title != oldDelegate.title;
}
@override
Widget build(
BuildContext context,
double shrinkOffset,
bool overlapsContent,
) {
final tempVal = maxExtent * 72 / 100;
final progress = shrinkOffset > tempVal ? 1.0 : shrinkOffset / tempVal;
final avatarMargin = _avatarMarginTween.lerp(progress);
final titleMargin = _titleMarginTween.lerp(progress);
final avatarAlign = _avatarAlignTween.lerp(progress);
final iconAlign = _iconAlignTween.lerp(progress);
final avatarSize = (1 - progress) * 200 + 32;
return Stack(
children: <Widget>[
AnimatedContainer(
duration: Duration(milliseconds: 100),
height: 80,
constraints: BoxConstraints(maxHeight: minExtent),
color: Colors.white,
),
Padding(
padding: avatarMargin,
child: Align(
alignment: avatarAlign,
child: SizedBox(
height: avatarSize,
width: avatarSize,
child: avatar,
),
),
),
Align(
alignment: Alignment.bottomRight,
child: Container(
height: progress < 0.4 ? 100 * (1 - progress) * 1.5 : 0,
decoration: BoxDecoration(
gradient: LinearGradient(
begin: Alignment.topCenter,
end: Alignment.bottomCenter,
colors: [
Colors.pink[200]!.withOpacity(0.05),
Colors.pink[400]!.withOpacity(0.8),
],
),
),
),
),
Padding(
padding: titleMargin,
child: Align(
alignment: avatarAlign,
child: Text(
title,
),
),
),
Padding(
padding: titleMargin,
child: Align(
alignment: iconAlign,
child: Padding(
padding: const EdgeInsets.only(right: 16),
child: GestureDetector(
onTap: () {},
child: Icon(
Icons.search,
size: 30,
color: progress < 0.4 ? Colors.white : Colors.black,
),
),
),
),
),
],
);
}
}
Also this answer might be helpful
Upvotes: 1
Reputation: 416
/// Flutter code sample for SliverAppBar
// This sample shows a [SliverAppBar] and it's behavior when using the
// [pinned], [snap] and [floating] parameters.
import 'package:flutter/material.dart';
void main() => runApp(MyApp());
/// This is the main application widget.
class MyApp extends StatelessWidget {
static const String _title = 'Flutter Code Sample';
@override
Widget build(BuildContext context) {
return const MaterialApp(
title: _title,
home: MyStatefulWidget(),
);
}
}
/// This is the stateful widget that the main application instantiates.
class MyStatefulWidget extends StatefulWidget {
const MyStatefulWidget();
@override
_MyStatefulWidgetState createState() => _MyStatefulWidgetState();
}
/// This is the private State class that goes with MyStatefulWidget.
class _MyStatefulWidgetState extends State<MyStatefulWidget> {
bool _pinned = true;
bool _snap = false;
bool _floating = false;
// [SliverAppBar]s are typically used in [CustomScrollView.slivers], which in
// turn can be placed in a [Scaffold.body].
@override
Widget build(BuildContext context) {
return Scaffold(
body: CustomScrollView(
slivers: <Widget>[
SliverAppBar(
pinned: _pinned,
snap: _snap,
floating: _floating,
expandedHeight: 160.0,
flexibleSpace: const FlexibleSpaceBar(
title: Text('SliverAppBar'),
background: FlutterLogo(),
),
),
const SliverToBoxAdapter(
child: SizedBox(
height: 20,
child: Center(
child: Text('Scroll to see the SliverAppBar in effect.'),
),
),
),
SliverList(
delegate: SliverChildBuilderDelegate(
(BuildContext context, int index) {
return Container(
color: index.isOdd ? Colors.white : Colors.black12,
height: 100.0,
child: Center(
child: Text('$index', textScaleFactor: 5),
),
);
},
childCount: 20,
),
),
],
),
bottomNavigationBar: BottomAppBar(
child: ButtonBar(
alignment: MainAxisAlignment.spaceEvenly,
children: <Widget>[
Row(
children: <Widget>[
const Text('pinned'),
Switch(
onChanged: (bool val) {
setState(() {
_pinned = val;
});
},
value: _pinned,
),
],
),
Row(
children: <Widget>[
const Text('snap'),
Switch(
onChanged: (bool val) {
setState(() {
_snap = val;
// Snapping only applies when the app bar is floating.
_floating = _floating || _snap;
});
},
value: _snap,
),
],
),
Row(
children: <Widget>[
const Text('floating'),
Switch(
onChanged: (bool val) {
setState(() {
_floating = val;
_snap = _snap && _floating;
});
},
value: _floating,
),
],
),
],
),
),
);
}
}
Source - https://api.flutter.dev/flutter/material/SliverAppBar-class.html
Upvotes: 1