mirror of
https://github.com/flutter/flutter.git
synced 2025-06-03 00:51:18 +00:00
Gallery animation demo back button update (#9853)
This commit is contained in:
parent
f752cd3844
commit
a6eb0a3e38
@ -15,6 +15,8 @@ import 'sections.dart';
|
||||
import 'widgets.dart';
|
||||
|
||||
const Color _kAppBackgroundColor = const Color(0xFF353662);
|
||||
const Duration _kScrollDuration = const Duration(milliseconds: 400);
|
||||
const Curve _kScrollCurve = Curves.fastOutSlowIn;
|
||||
|
||||
// This app's contents start out at _kHeadingMaxHeight and they function like
|
||||
// an appbar. Initially the appbar occupies most of the screen and its section
|
||||
@ -449,6 +451,13 @@ class _AnimationDemoHomeState extends State<AnimationDemoHome> {
|
||||
);
|
||||
}
|
||||
|
||||
void _handleBackButton(double midScrollOffset) {
|
||||
if (_scrollController.offset >= midScrollOffset)
|
||||
_scrollController.animateTo(0.0, curve: _kScrollCurve, duration: _kScrollDuration);
|
||||
else
|
||||
Navigator.of(context).maybePop();
|
||||
}
|
||||
|
||||
// Only enable paging for the heading when the user has scrolled to midScrollOffset.
|
||||
// Paging is enabled/disabled by setting the heading's PageView scroll physics.
|
||||
bool _handleScrollNotification(ScrollNotification notification, double midScrollOffset) {
|
||||
@ -466,18 +475,16 @@ class _AnimationDemoHomeState extends State<AnimationDemoHome> {
|
||||
}
|
||||
|
||||
void _maybeScroll(double midScrollOffset, int pageIndex, double xOffset) {
|
||||
const Duration duration = const Duration(milliseconds: 400);
|
||||
const Curve curve = Curves.fastOutSlowIn;
|
||||
if (_scrollController.offset < midScrollOffset) {
|
||||
// Scroll the overall list to the point where only one section card shows.
|
||||
// At the same time scroll the PageViews to the page at pageIndex.
|
||||
_headingPageController.animateToPage(pageIndex, curve: curve, duration: duration);
|
||||
_scrollController.animateTo(midScrollOffset, curve: curve, duration: duration);
|
||||
_headingPageController.animateToPage(pageIndex, curve: _kScrollCurve, duration: _kScrollDuration);
|
||||
_scrollController.animateTo(midScrollOffset, curve: _kScrollCurve, duration: _kScrollDuration);
|
||||
} else {
|
||||
// One one section card is showing: scroll one page forward or back.
|
||||
final double centerX = _headingPageController.position.viewportDimension / 2.0;
|
||||
final int newPageIndex = xOffset > centerX ? pageIndex + 1 : pageIndex - 1;
|
||||
_headingPageController.animateToPage(newPageIndex, curve: curve, duration: duration);
|
||||
_headingPageController.animateToPage(newPageIndex, curve: _kScrollCurve, duration: _kScrollDuration);
|
||||
}
|
||||
}
|
||||
|
||||
@ -605,9 +612,15 @@ class _AnimationDemoHomeState extends State<AnimationDemoHome> {
|
||||
new Positioned(
|
||||
top: statusBarHeight,
|
||||
left: 0.0,
|
||||
child: const IconTheme(
|
||||
child: new IconTheme(
|
||||
data: const IconThemeData(color: Colors.white),
|
||||
child: const BackButton(),
|
||||
child: new IconButton(
|
||||
icon: const BackButtonIcon(),
|
||||
tooltip: 'Back',
|
||||
onPressed: () {
|
||||
_handleBackButton(appBarMidScrollOffset);
|
||||
}
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
|
@ -9,6 +9,35 @@ import 'icon_button.dart';
|
||||
import 'icons.dart';
|
||||
import 'theme.dart';
|
||||
|
||||
/// A "back" icon that's appropriate for the current [TargetPlatform].
|
||||
///
|
||||
/// See also:
|
||||
///
|
||||
/// * [BackButton], an [IconButton] with a [BackButtonIcon] that calls
|
||||
/// [Navigator.maybePop] to return to the previous route.
|
||||
/// * [IconButton], which is a more general widget for creating buttons
|
||||
/// with icons.
|
||||
/// * [Icon], a material design icon.
|
||||
class BackButtonIcon extends StatelessWidget {
|
||||
const BackButtonIcon({ Key key }) : super(key: key);
|
||||
|
||||
/// Returns tha appropriate "back" icon for the given `platform`.
|
||||
static IconData _getIconData(TargetPlatform platform) {
|
||||
switch (platform) {
|
||||
case TargetPlatform.android:
|
||||
case TargetPlatform.fuchsia:
|
||||
return Icons.arrow_back;
|
||||
case TargetPlatform.iOS:
|
||||
return Icons.arrow_back_ios;
|
||||
}
|
||||
assert(false);
|
||||
return null;
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) => new Icon(_getIconData(Theme.of(context).platform));
|
||||
}
|
||||
|
||||
/// A material design back button.
|
||||
///
|
||||
/// A [BackButton] is an [IconButton] with a "back" icon appropriate for the
|
||||
@ -27,6 +56,8 @@ import 'theme.dart';
|
||||
///
|
||||
/// * [AppBar], which automatically uses a [BackButton] in its
|
||||
/// [AppBar.leading] slot when appropriate.
|
||||
/// * [BackButtonIcon], which is useful if you need to create a back button
|
||||
/// that responds differently to being pressed.
|
||||
/// * [IconButton], which is a more general widget for creating buttons with
|
||||
/// icons.
|
||||
/// * [CloseButton], an alternative which may be more appropriate for leaf
|
||||
@ -36,27 +67,14 @@ class BackButton extends StatelessWidget {
|
||||
/// target platform.
|
||||
const BackButton({ Key key }) : super(key: key);
|
||||
|
||||
/// Returns tha appropriate "back" icon for the given `platform`.
|
||||
static IconData getIconData(TargetPlatform platform) {
|
||||
switch (platform) {
|
||||
case TargetPlatform.android:
|
||||
case TargetPlatform.fuchsia:
|
||||
return Icons.arrow_back;
|
||||
case TargetPlatform.iOS:
|
||||
return Icons.arrow_back_ios;
|
||||
}
|
||||
assert(false);
|
||||
return null;
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return new IconButton(
|
||||
icon: new Icon(getIconData(Theme.of(context).platform)),
|
||||
icon: const BackButtonIcon(),
|
||||
tooltip: 'Back', // TODO(ianh): Figure out how to localize this string
|
||||
onPressed: () {
|
||||
Navigator.of(context).maybePop();
|
||||
},
|
||||
}
|
||||
);
|
||||
}
|
||||
}
|
||||
|
@ -32,4 +32,31 @@ void main() {
|
||||
|
||||
expect(find.text('Home'), findsOneWidget);
|
||||
});
|
||||
|
||||
testWidgets('BackButton icon', (WidgetTester tester) async {
|
||||
final Key iOSKey = new UniqueKey();
|
||||
final Key androidKey = new UniqueKey();
|
||||
|
||||
|
||||
await tester.pumpWidget(
|
||||
new MaterialApp(
|
||||
home: new Column(
|
||||
children: <Widget>[
|
||||
new Theme(
|
||||
data: new ThemeData(platform: TargetPlatform.iOS),
|
||||
child: new BackButtonIcon(key: iOSKey),
|
||||
),
|
||||
new Theme(
|
||||
data: new ThemeData(platform: TargetPlatform.android),
|
||||
child: new BackButtonIcon(key: androidKey),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
);
|
||||
|
||||
final Icon iOSIcon = tester.widget(find.descendant(of: find.byKey(iOSKey), matching: find.byType(Icon)));
|
||||
final Icon androidIcon = tester.widget(find.descendant(of: find.byKey(androidKey), matching: find.byType(Icon)));
|
||||
expect(iOSIcon == androidIcon, false);
|
||||
});
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user