Created
March 14, 2020 03:03
-
-
Save lucasjinreal/80fc67e781d565874c14bf28912ef2d1 to your computer and use it in GitHub Desktop.
open container animation
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// Copyright 2019 The Flutter Authors. All rights reserved. | |
// Use of this source code is governed by a BSD-style license that can be | |
// found in the LICENSE file. | |
import 'package:flutter/material.dart'; | |
import 'package:animations/animations.dart'; | |
const String _loremIpsumParagraph = | |
'Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod ' | |
'tempor incididunt ut labore et dolore magna aliqua. Vulputate dignissim ' | |
'suspendisse in est. Ut ornare lectus sit amet. Eget nunc lobortis mattis ' | |
'aliquam faucibus purus in. Hendrerit gravida rutrum quisque non tellus ' | |
'orci ac auctor. Mattis aliquam faucibus purus in massa. Tellus rutrum ' | |
'tellus pellentesque eu tincidunt tortor. Nunc eget lorem dolor sed. Nulla ' | |
'at volutpat diam ut venenatis tellus in metus. Tellus cras adipiscing enim ' | |
'eu turpis. Pretium fusce id velit ut tortor. Adipiscing enim eu turpis ' | |
'egestas pretium. Quis varius quam quisque id. Blandit aliquam etiam erat ' | |
'velit scelerisque. In nisl nisi scelerisque eu. Semper risus in hendrerit ' | |
'gravida rutrum quisque. Suspendisse in est ante in nibh mauris cursus ' | |
'mattis molestie. Adipiscing elit duis tristique sollicitudin nibh sit ' | |
'amet commodo nulla. Pretium viverra suspendisse potenti nullam ac tortor ' | |
'vitae.\n' | |
'\n' | |
'Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod ' | |
'tempor incididunt ut labore et dolore magna aliqua. Vulputate dignissim ' | |
'suspendisse in est. Ut ornare lectus sit amet. Eget nunc lobortis mattis ' | |
'aliquam faucibus purus in. Hendrerit gravida rutrum quisque non tellus ' | |
'orci ac auctor. Mattis aliquam faucibus purus in massa. Tellus rutrum ' | |
'tellus pellentesque eu tincidunt tortor. Nunc eget lorem dolor sed. Nulla ' | |
'at volutpat diam ut venenatis tellus in metus. Tellus cras adipiscing enim ' | |
'eu turpis. Pretium fusce id velit ut tortor. Adipiscing enim eu turpis ' | |
'egestas pretium. Quis varius quam quisque id. Blandit aliquam etiam erat ' | |
'velit scelerisque. In nisl nisi scelerisque eu. Semper risus in hendrerit ' | |
'gravida rutrum quisque. Suspendisse in est ante in nibh mauris cursus ' | |
'mattis molestie. Adipiscing elit duis tristique sollicitudin nibh sit ' | |
'amet commodo nulla. Pretium viverra suspendisse potenti nullam ac tortor ' | |
'vitae'; | |
const double _fabDimension = 56.0; | |
/// The demo page for [OpenContainerTransform]. | |
class OpenContainerTransformDemo extends StatefulWidget { | |
@override | |
_OpenContainerTransformDemoState createState() { | |
return _OpenContainerTransformDemoState(); | |
} | |
} | |
class _OpenContainerTransformDemoState | |
extends State<OpenContainerTransformDemo> { | |
ContainerTransitionType _transitionType = ContainerTransitionType.fade; | |
void _showSettingsBottomModalSheet(BuildContext context) { | |
showModalBottomSheet<void>( | |
context: context, | |
builder: (BuildContext context) { | |
return StatefulBuilder( | |
builder: (BuildContext context, StateSetter setModalState) { | |
return Container( | |
height: 125, | |
padding: const EdgeInsets.all(15.0), | |
child: Column( | |
crossAxisAlignment: CrossAxisAlignment.start, | |
children: <Widget>[ | |
Text( | |
'这是个啥?', | |
style: Theme.of(context).textTheme.caption, | |
), | |
const SizedBox(height: 12), | |
ToggleButtons( | |
borderRadius: BorderRadius.circular(2.0), | |
selectedBorderColor: Theme.of(context).colorScheme.primary, | |
onPressed: (int index) { | |
setModalState(() { | |
setState(() { | |
_transitionType = index == 0 | |
? ContainerTransitionType.fade | |
: ContainerTransitionType.fadeThrough; | |
}); | |
}); | |
}, | |
isSelected: <bool>[ | |
_transitionType == ContainerTransitionType.fade, | |
_transitionType == ContainerTransitionType.fadeThrough, | |
], | |
children: const <Widget>[ | |
Text('渐变?'), | |
Padding( | |
padding: EdgeInsets.symmetric(horizontal: 10.0), | |
child: Text('FADE THROUGH'), | |
), | |
], | |
), | |
], | |
), | |
); | |
}, | |
); | |
}, | |
); | |
} | |
@override | |
Widget build(BuildContext context) { | |
return Scaffold( | |
appBar: AppBar( | |
title: const Text('Container 的变换动画'), | |
actions: <Widget>[ | |
IconButton( | |
icon: Icon(Icons.settings), | |
onPressed: () { | |
_showSettingsBottomModalSheet(context); | |
}, | |
), | |
], | |
), | |
body: ListView( | |
padding: const EdgeInsets.all(8.0), | |
children: <Widget>[ | |
_OpenContainerWrapper( | |
transitionType: _transitionType, | |
closedBuilder: (BuildContext _, VoidCallback openContainer) { | |
return _ExampleCard(openContainer: openContainer); | |
}, | |
), | |
const SizedBox(height: 16.0), | |
_OpenContainerWrapper( | |
transitionType: _transitionType, | |
closedBuilder: (BuildContext _, VoidCallback openContainer) { | |
return _ExampleSingleTile(openContainer: openContainer); | |
}, | |
), | |
const SizedBox(height: 16.0), | |
Row( | |
children: <Widget>[ | |
Expanded( | |
child: _OpenContainerWrapper( | |
transitionType: _transitionType, | |
closedBuilder: (BuildContext _, VoidCallback openContainer) { | |
return _SmallerCard( | |
openContainer: openContainer, | |
subtitle: '第二次及文字', | |
); | |
}, | |
), | |
), | |
const SizedBox(width: 8.0), | |
Expanded( | |
child: _OpenContainerWrapper( | |
transitionType: _transitionType, | |
closedBuilder: (BuildContext _, VoidCallback openContainer) { | |
return _SmallerCard( | |
openContainer: openContainer, | |
subtitle: 'Secondary text', | |
); | |
}, | |
), | |
), | |
], | |
), | |
const SizedBox(height: 16.0), | |
Row( | |
children: <Widget>[ | |
Expanded( | |
child: _OpenContainerWrapper( | |
transitionType: _transitionType, | |
closedBuilder: (BuildContext _, VoidCallback openContainer) { | |
return _SmallerCard( | |
openContainer: openContainer, | |
subtitle: 'Secondary', | |
); | |
}, | |
), | |
), | |
const SizedBox(width: 8.0), | |
Expanded( | |
child: _OpenContainerWrapper( | |
transitionType: _transitionType, | |
closedBuilder: (BuildContext _, VoidCallback openContainer) { | |
return _SmallerCard( | |
openContainer: openContainer, | |
subtitle: 'Secondary', | |
); | |
}, | |
), | |
), | |
const SizedBox(width: 8.0), | |
Expanded( | |
child: _OpenContainerWrapper( | |
transitionType: _transitionType, | |
closedBuilder: (BuildContext _, VoidCallback openContainer) { | |
return _SmallerCard( | |
openContainer: openContainer, | |
subtitle: 'Secondary', | |
); | |
}, | |
), | |
), | |
], | |
), | |
const SizedBox(height: 16.0), | |
...List<Widget>.generate(10, (int index) { | |
return OpenContainer( | |
transitionType: _transitionType, | |
openBuilder: (BuildContext _, VoidCallback openContainer) { | |
return _DetailsPage(); | |
}, | |
tappable: false, | |
closedShape: const RoundedRectangleBorder(), | |
closedElevation: 0.0, | |
closedBuilder: (BuildContext _, VoidCallback openContainer) { | |
return ListTile( | |
leading: Image.asset( | |
'assets/avatar_logo.png', | |
width: 40, | |
), | |
onTap: openContainer, | |
title: Text('列表元素 ${index + 1}'), | |
subtitle: const Text('Secondary text'), | |
); | |
}, | |
); | |
}), | |
], | |
), | |
floatingActionButton: OpenContainer( | |
transitionType: _transitionType, | |
openBuilder: (BuildContext context, VoidCallback _) { | |
return _DetailsPage(); | |
}, | |
closedElevation: 6.0, | |
closedShape: const RoundedRectangleBorder( | |
borderRadius: BorderRadius.all( | |
Radius.circular(_fabDimension / 2), | |
), | |
), | |
closedColor: Theme.of(context).colorScheme.secondary, | |
closedBuilder: (BuildContext context, VoidCallback openContainer) { | |
return SizedBox( | |
height: _fabDimension, | |
width: _fabDimension, | |
child: Center( | |
child: Icon( | |
Icons.add, | |
color: Theme.of(context).colorScheme.onSecondary, | |
), | |
), | |
); | |
}, | |
), | |
); | |
} | |
} | |
class _OpenContainerWrapper extends StatelessWidget { | |
const _OpenContainerWrapper({ | |
this.closedBuilder, | |
this.transitionType, | |
}); | |
final OpenContainerBuilder closedBuilder; | |
final ContainerTransitionType transitionType; | |
@override | |
Widget build(BuildContext context) { | |
return OpenContainer( | |
transitionType: transitionType, | |
openBuilder: (BuildContext context, VoidCallback _) { | |
return _DetailsPage(); | |
}, | |
tappable: false, | |
closedBuilder: closedBuilder, | |
); | |
} | |
} | |
class _ExampleCard extends StatelessWidget { | |
const _ExampleCard({this.openContainer}); | |
final VoidCallback openContainer; | |
@override | |
Widget build(BuildContext context) { | |
return _InkWellOverlay( | |
openContainer: openContainer, | |
height: 300, | |
child: Column( | |
crossAxisAlignment: CrossAxisAlignment.stretch, | |
children: <Widget>[ | |
Expanded( | |
child: Container( | |
color: Colors.black38, | |
child: Center( | |
child: Image.asset( | |
'assets/placeholder_image.png', | |
width: 100, | |
), | |
), | |
), | |
), | |
const ListTile( | |
title: Text('示例的卡片'), | |
subtitle: Text('Secondary text'), | |
), | |
Padding( | |
padding: const EdgeInsets.only( | |
left: 16.0, | |
right: 16.0, | |
bottom: 16.0, | |
), | |
child: Text( | |
'Lorem ipsum dolor sit amet, consectetur ' | |
'adipiscing elit, sed do eiusmod tempor.', | |
style: Theme.of(context) | |
.textTheme | |
.body2 | |
.copyWith(color: Colors.black54), | |
), | |
), | |
], | |
), | |
); | |
} | |
} | |
class _SmallerCard extends StatelessWidget { | |
const _SmallerCard({ | |
this.openContainer, | |
this.subtitle, | |
}); | |
final VoidCallback openContainer; | |
final String subtitle; | |
@override | |
Widget build(BuildContext context) { | |
return _InkWellOverlay( | |
openContainer: openContainer, | |
height: 225, | |
child: Column( | |
crossAxisAlignment: CrossAxisAlignment.start, | |
children: <Widget>[ | |
Container( | |
color: Colors.black38, | |
height: 150, | |
child: Center( | |
child: Image.asset( | |
'assets/placeholder_image.png', | |
width: 80, | |
), | |
), | |
), | |
Expanded( | |
child: Padding( | |
padding: const EdgeInsets.all(10.0), | |
child: Column( | |
mainAxisAlignment: MainAxisAlignment.center, | |
crossAxisAlignment: CrossAxisAlignment.start, | |
children: <Widget>[ | |
Text( | |
'更小的卡片', | |
style: Theme.of(context).textTheme.headline, | |
), | |
const SizedBox(height: 4), | |
Text( | |
subtitle, | |
style: Theme.of(context).textTheme.caption, | |
), | |
], | |
), | |
), | |
), | |
], | |
), | |
); | |
} | |
} | |
class _ExampleSingleTile extends StatelessWidget { | |
const _ExampleSingleTile({this.openContainer}); | |
final VoidCallback openContainer; | |
@override | |
Widget build(BuildContext context) { | |
const double height = 100.0; | |
return _InkWellOverlay( | |
openContainer: openContainer, | |
height: height, | |
child: Row( | |
children: <Widget>[ | |
Container( | |
color: Colors.black38, | |
height: height, | |
width: height, | |
child: Center( | |
child: Image.asset( | |
'assets/placeholder_image.png', | |
width: 60, | |
), | |
), | |
), | |
Expanded( | |
child: Padding( | |
padding: const EdgeInsets.all(20.0), | |
child: Column( | |
crossAxisAlignment: CrossAxisAlignment.start, | |
children: <Widget>[ | |
Text( | |
'单独的一行卡片', | |
style: Theme.of(context).textTheme.subtitle, | |
), | |
const SizedBox(height: 8), | |
Text( | |
'Lorem ipsum dolor sit amet, consectetur ' | |
'adipiscing elit,', | |
style: Theme.of(context).textTheme.caption), | |
], | |
), | |
), | |
), | |
], | |
), | |
); | |
} | |
} | |
class _InkWellOverlay extends StatelessWidget { | |
const _InkWellOverlay({ | |
this.openContainer, | |
this.width, | |
this.height, | |
this.child, | |
}); | |
final VoidCallback openContainer; | |
final double width; | |
final double height; | |
final Widget child; | |
@override | |
Widget build(BuildContext context) { | |
return SizedBox( | |
height: height, | |
width: width, | |
child: InkWell( | |
onTap: openContainer, | |
child: child, | |
), | |
); | |
} | |
} | |
class _DetailsPage extends StatelessWidget { | |
@override | |
Widget build(BuildContext context) { | |
return Scaffold( | |
appBar: AppBar(title: const Text('细节页面 page')), | |
body: ListView( | |
children: <Widget>[ | |
Container( | |
color: Colors.black38, | |
height: 250, | |
child: Padding( | |
padding: const EdgeInsets.all(70.0), | |
child: Image.asset( | |
'assets/placeholder_image.png', | |
), | |
), | |
), | |
Padding( | |
padding: const EdgeInsets.all(20.0), | |
child: Column( | |
crossAxisAlignment: CrossAxisAlignment.start, | |
children: <Widget>[ | |
Text( | |
'这是i标题', | |
style: Theme.of(context).textTheme.headline.copyWith( | |
color: Colors.black54, | |
fontSize: 30.0, | |
), | |
), | |
const SizedBox(height: 10), | |
Text( | |
_loremIpsumParagraph, | |
style: Theme.of(context).textTheme.body2.copyWith( | |
color: Colors.black54, | |
height: 1.5, | |
fontSize: 16.0, | |
), | |
), | |
], | |
), | |
), | |
], | |
), | |
); | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment