Skip to content

Instantly share code, notes, and snippets.

@letsar
Last active September 1, 2018 08:02
Show Gist options
  • Save letsar/56e2a1b29d54e7515f09a58a543c49ab to your computer and use it in GitHub Desktop.
Save letsar/56e2a1b29d54e7515f09a58a543c49ab to your computer and use it in GitHub Desktop.
import 'dart:async';
import 'package:flutter/material.dart';
const _kDuration = const Duration(milliseconds: 4000);
const _kActionSize = 64.0;
const _kCount = 3;
const _kAnimInterval01 = const Interval(.00, .30);
const _kAnimInterval02 = const Interval(.00, .30);
const _kAnimInterval03 = const Interval(.30, .60);
const _kAnimInterval04 = const Interval(.60, .90);
const _kAnimInterval05 = const Interval(.60, .90);
const archiveAction = const IconSlideAction(
icon: Icons.archive,
color: Colors.blue,
caption: 'Archive',
);
const shareAction = const IconSlideAction(
icon: Icons.share,
color: Colors.indigo,
caption: 'Share',
);
void main() => runApp(
MaterialApp(
home: Material(
child: SlidableDrawerDelegateDemo(),
),
),
);
class SlidableDrawerDelegateDemo extends StatefulWidget {
@override
_SlidableDrawerDelegateDemoState createState() =>
new _SlidableDrawerDelegateDemoState();
}
class _SlidableDrawerDelegateDemoState extends State<SlidableDrawerDelegateDemo>
with TickerProviderStateMixin {
AnimationController _controller;
@override
void initState() {
super.initState();
_controller = AnimationController(duration: _kDuration, vsync: this);
}
Future<Null> _playAnimation() async {
try {
await _controller.forward().orCancel;
await _controller.reverse().orCancel;
} on TickerCanceled {
// the animation got canceled, probably because we were disposed
}
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('Slidable Drawer Delegate Animation'),
),
body: GestureDetector(
behavior: HitTestBehavior.opaque,
onTap: () => _playAnimation(),
child: Padding(
padding: const EdgeInsets.all(8.0),
child: Center(
child: SlidableDrawerDelegateAnimation(
controller: _controller.view,
),
),
),
),
);
}
}
class SlidableDrawerDelegateAnimation extends StatelessWidget {
SlidableDrawerDelegateAnimation({
Key key,
this.controller,
}) : dxPositions = <Animation<Offset>>[
Tween<Offset>(
begin: Offset(-1.0, 0.0),
end: Offset(1.0, 0.0),
).animate(
CurvedAnimation(
parent: controller,
curve: _kAnimInterval03,
),
),
Tween<Offset>(
begin: Offset(-1.0, 0.0),
end: Offset(0.0, 0.0),
).animate(
CurvedAnimation(
parent: controller,
curve: _kAnimInterval03,
),
),
Tween<Offset>(
begin: Offset(0.0, 0.0),
end: Offset(0.5, 0.0),
).animate(
CurvedAnimation(
parent: controller,
curve: _kAnimInterval03,
),
),
],
dyPositions1 = List.generate(
_kCount,
(i) => Tween<Offset>(
begin: Offset.zero,
end: Offset(0.0, -i.toDouble() / 2),
).animate(
CurvedAnimation(
parent: controller,
curve: _kAnimInterval01,
),
),
),
dyPositions2 = List.generate(
_kCount,
(i) => Tween<Offset>(
begin: Offset.zero,
end: Offset(0.0, i.toDouble() / 2),
).animate(
CurvedAnimation(
parent: controller,
curve: _kAnimInterval04,
),
),
),
skewTransform1 = Tween<double>(begin: 0.0, end: 0.5).animate(
CurvedAnimation(
parent: controller,
curve: _kAnimInterval02,
),
),
skewTransform2 = Tween<double>(begin: 0.0, end: -0.5).animate(
CurvedAnimation(
parent: controller,
curve: _kAnimInterval05,
),
),
super(key: key);
final Animation<double> controller;
final List<Animation<Offset>> dyPositions1;
final List<Animation<Offset>> dyPositions2;
final List<Animation<Offset>> dxPositions;
final Animation<double> skewTransform1;
final Animation<double> skewTransform2;
Widget _buildAnimation(BuildContext context, Widget child) {
return Container(
child: SkewTransition(
skew: skewTransform1,
child: SkewTransition(
skew: skewTransform2,
child: Container(
width: _kActionSize * 4,
height: 256.0,
color: Colors.black87,
child: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
_buildListTile(context, 0),
Stack(
children: List.generate(_kCount, (i) {
return SlideTransition(
position: dyPositions1[i],
child: SlideTransition(
position: dxPositions[i],
child: SlideTransition(
position: dyPositions2[i],
child: _buildWidget(context, i),
),
),
);
}),
),
_buildListTile(context, 2),
],
),
),
),
),
),
);
}
Widget _buildWidget(BuildContext context, int index) {
switch (index) {
case 0:
return shareAction;
case 1:
return archiveAction;
case 2:
return _buildListTile(context, 1);
}
return null;
}
Widget _buildListTile(BuildContext context, int index) {
return Container(
color: Colors.grey.shade200,
width: _kActionSize * 4,
height: _kActionSize,
child: ListTile(
leading: CircleAvatar(
backgroundColor: Colors.green,
child: Text('$index'),
foregroundColor: Colors.white,
),
title: Text('Title'),
subtitle: Text('Subtitle'),
),
);
}
@override
Widget build(BuildContext context) {
return AnimatedBuilder(
builder: _buildAnimation,
animation: controller,
);
}
}
/// Animates the skew of transformed widget.
class SkewTransition extends AnimatedWidget {
/// Creates a skew transition.
///
/// The [skew] argument must not be null.
const SkewTransition({
Key key,
@required Animation<double> skew,
this.child,
}) : super(key: key, listenable: skew);
/// The animation that controls the skew of the child.
Animation<double> get skew => listenable;
/// The widget below this widget in the tree.
///
/// {@macro flutter.widgets.child}
final Widget child;
@override
Widget build(BuildContext context) {
final double skewValue = skew.value;
final Matrix4 transform = new Matrix4.skewX(skewValue);
return new Transform(
transform: transform,
child: child,
);
}
}
class IconSlideAction extends StatelessWidget {
/// Creates a slide action with an icon, a [caption] if set and a
/// background color.
///
/// The [closeOnTap] argument must not be null.
const IconSlideAction({
Key key,
@required this.icon,
this.caption,
this.color,
}) : super(key: key);
final IconData icon;
final String caption;
/// The background color.
///
/// Defaults to true.
final Color color;
@override
Widget build(BuildContext context) {
final Color foregroundColor =
ThemeData.estimateBrightnessForColor(color) == Brightness.light
? Colors.black
: Colors.white;
final Text textWidget = new Text(
caption ?? '',
overflow: TextOverflow.ellipsis,
style: Theme.of(context)
.primaryTextTheme
.caption
.copyWith(color: foregroundColor),
);
return Container(
color: color,
width: _kActionSize,
height: _kActionSize,
child: new Center(
child: Column(
mainAxisSize: MainAxisSize.min,
children: <Widget>[
new Flexible(
child: new Icon(
icon,
color: foregroundColor,
),
),
new Flexible(child: textWidget),
],
),
),
);
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment