Remove long-deprecated TwoLevelList (#26238)
This commit is contained in:
parent
c8f72ac596
commit
51732aee3b
@ -6,8 +6,8 @@ import 'package:flutter/material.dart';
|
||||
|
||||
import '../../gallery/demo.dart';
|
||||
|
||||
class TwoLevelListDemo extends StatelessWidget {
|
||||
static const String routeName = '/material/two-level-list';
|
||||
class ExpansionTileListDemo extends StatelessWidget {
|
||||
static const String routeName = '/material/expansion-tile-list';
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
@ -14,6 +14,7 @@ export 'dialog_demo.dart';
|
||||
export 'drawer_demo.dart';
|
||||
export 'elevation_demo.dart';
|
||||
export 'expansion_panels_demo.dart';
|
||||
export 'expansion_tile_list_demo.dart';
|
||||
export 'grid_list_demo.dart';
|
||||
export 'icons_demo.dart';
|
||||
export 'leave_behind_demo.dart';
|
||||
@ -34,4 +35,3 @@ export 'tabs_demo.dart';
|
||||
export 'tabs_fab_demo.dart';
|
||||
export 'text_form_field_demo.dart';
|
||||
export 'tooltip_demo.dart';
|
||||
export 'two_level_list_demo.dart';
|
||||
|
@ -243,9 +243,9 @@ List<GalleryDemo> _buildGalleryDemos() {
|
||||
subtitle: 'A list with one sub-list level',
|
||||
icon: GalleryIcons.expand_all,
|
||||
category: _kMaterialComponents,
|
||||
routeName: TwoLevelListDemo.routeName,
|
||||
routeName: ExpansionTileListDemo.routeName,
|
||||
documentationUrl: 'https://docs.flutter.io/flutter/material/ExpansionTile-class.html',
|
||||
buildRoute: (BuildContext context) => TwoLevelListDemo(),
|
||||
buildRoute: (BuildContext context) => ExpansionTileListDemo(),
|
||||
),
|
||||
GalleryDemo(
|
||||
title: 'Expansion panels',
|
||||
|
@ -229,9 +229,9 @@ void main() {
|
||||
handle.dispose();
|
||||
});
|
||||
|
||||
testWidgets('two_level_list_demo', (WidgetTester tester) async {
|
||||
testWidgets('expansion_tile_list_demo', (WidgetTester tester) async {
|
||||
final SemanticsHandle handle = tester.ensureSemantics();
|
||||
await tester.pumpWidget(MaterialApp(home: TwoLevelListDemo()));
|
||||
await tester.pumpWidget(MaterialApp(home: ExpansionTileListDemo()));
|
||||
await expectLater(tester, meetsGuideline(androidTapTargetGuideline));
|
||||
handle.dispose();
|
||||
});
|
||||
@ -462,9 +462,9 @@ void main() {
|
||||
handle.dispose();
|
||||
});
|
||||
|
||||
testWidgets('two_level_list_demo', (WidgetTester tester) async {
|
||||
testWidgets('expansion_tile_list_demo', (WidgetTester tester) async {
|
||||
final SemanticsHandle handle = tester.ensureSemantics();
|
||||
await tester.pumpWidget(MaterialApp(home: TwoLevelListDemo()));
|
||||
await tester.pumpWidget(MaterialApp(home: ExpansionTileListDemo()));
|
||||
await expectLater(tester, meetsGuideline(labeledTapTargetGuideline));
|
||||
handle.dispose();
|
||||
});
|
||||
@ -775,11 +775,11 @@ void main() {
|
||||
handle.dispose();
|
||||
});
|
||||
|
||||
testWidgets('two_level_list_demo $themeName', (WidgetTester tester) async {
|
||||
testWidgets('expansion_tile_list_demo $themeName', (WidgetTester tester) async {
|
||||
final AutomatedTestWidgetsFlutterBinding binding = tester.binding;
|
||||
binding.addTime(const Duration(seconds: 3));
|
||||
final SemanticsHandle handle = tester.ensureSemantics();
|
||||
await tester.pumpWidget(MaterialApp(theme: theme, home: TwoLevelListDemo()));
|
||||
await tester.pumpWidget(MaterialApp(theme: theme, home: ExpansionTileListDemo()));
|
||||
await expectLater(tester, meetsGuideline(textContrastGuideline));
|
||||
handle.dispose();
|
||||
});
|
||||
|
@ -105,7 +105,6 @@ export 'src/material/time.dart';
|
||||
export 'src/material/time_picker.dart';
|
||||
export 'src/material/toggleable.dart';
|
||||
export 'src/material/tooltip.dart';
|
||||
export 'src/material/two_level_list.dart';
|
||||
export 'src/material/typography.dart';
|
||||
export 'src/material/user_accounts_drawer_header.dart';
|
||||
export 'widgets.dart';
|
||||
|
@ -1,288 +0,0 @@
|
||||
// Copyright 2016 The Chromium 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/widgets.dart';
|
||||
|
||||
import 'colors.dart';
|
||||
import 'icons.dart';
|
||||
import 'list_tile.dart';
|
||||
import 'theme.dart';
|
||||
import 'theme_data.dart';
|
||||
|
||||
/// This enum is deprecated. Please use [ListTileTheme] instead.
|
||||
enum MaterialListType {
|
||||
/// A list tile that contains a single line of text.
|
||||
oneLine,
|
||||
|
||||
/// A list tile that contains a [CircleAvatar] followed by a single line of text.
|
||||
oneLineWithAvatar,
|
||||
|
||||
/// A list tile that contains two lines of text.
|
||||
twoLine,
|
||||
|
||||
/// A list tile that contains three lines of text.
|
||||
threeLine,
|
||||
}
|
||||
|
||||
/// This constant is deprecated. The [ListTile] class sizes itself based on
|
||||
/// its content and [ListTileTheme].
|
||||
@deprecated
|
||||
Map<MaterialListType, double> kListTileExtent = const <MaterialListType, double>{
|
||||
MaterialListType.oneLine: 48.0,
|
||||
MaterialListType.oneLineWithAvatar: 56.0,
|
||||
MaterialListType.twoLine: 72.0,
|
||||
MaterialListType.threeLine: 88.0,
|
||||
};
|
||||
|
||||
const Duration _kExpand = Duration(milliseconds: 200);
|
||||
|
||||
/// This class is deprecated. Please use [ListTile] instead.
|
||||
@deprecated
|
||||
class TwoLevelListItem extends StatelessWidget {
|
||||
/// Creates an item in a two-level list.
|
||||
const TwoLevelListItem({
|
||||
Key key,
|
||||
this.leading,
|
||||
@required this.title,
|
||||
this.trailing,
|
||||
this.enabled = true,
|
||||
this.onTap,
|
||||
this.onLongPress
|
||||
}) : assert(title != null),
|
||||
super(key: key);
|
||||
|
||||
/// A widget to display before the title.
|
||||
///
|
||||
/// Typically a [CircleAvatar] widget.
|
||||
final Widget leading;
|
||||
|
||||
/// The primary content of the list item.
|
||||
///
|
||||
/// Typically a [Text] widget.
|
||||
final Widget title;
|
||||
|
||||
/// A widget to display after the title.
|
||||
///
|
||||
/// Typically an [Icon] widget.
|
||||
final Widget trailing;
|
||||
|
||||
/// Whether this list item is interactive.
|
||||
///
|
||||
/// If false, this list item is styled with the disabled color from the
|
||||
/// current [Theme] and the [onTap] and [onLongPress] callbacks are
|
||||
/// inoperative.
|
||||
final bool enabled;
|
||||
|
||||
/// Called when the user taps this list item.
|
||||
///
|
||||
/// Inoperative if [enabled] is false.
|
||||
final GestureTapCallback onTap;
|
||||
|
||||
/// Called when the user long-presses on this list item.
|
||||
///
|
||||
/// Inoperative if [enabled] is false.
|
||||
final GestureLongPressCallback onLongPress;
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final TwoLevelList parentList = context.ancestorWidgetOfExactType(TwoLevelList);
|
||||
assert(parentList != null);
|
||||
|
||||
return SizedBox(
|
||||
height: kListTileExtent[parentList.type],
|
||||
child: ListTile(
|
||||
leading: leading,
|
||||
title: title,
|
||||
trailing: trailing,
|
||||
enabled: enabled,
|
||||
onTap: onTap,
|
||||
onLongPress: onLongPress
|
||||
)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/// This class is deprecated. Please use [ExpansionTile] instead.
|
||||
@deprecated
|
||||
class TwoLevelSublist extends StatefulWidget {
|
||||
/// Creates an item in a two-level list that can expand and collapse.
|
||||
const TwoLevelSublist({
|
||||
Key key,
|
||||
this.leading,
|
||||
@required this.title,
|
||||
this.backgroundColor,
|
||||
this.onOpenChanged,
|
||||
this.children = const <Widget>[],
|
||||
}) : super(key: key);
|
||||
|
||||
/// A widget to display before the title.
|
||||
///
|
||||
/// Typically a [CircleAvatar] widget.
|
||||
final Widget leading;
|
||||
|
||||
/// The primary content of the list item.
|
||||
///
|
||||
/// Typically a [Text] widget.
|
||||
final Widget title;
|
||||
|
||||
/// Called when the sublist expands or collapses.
|
||||
///
|
||||
/// When the sublist starts expanding, this function is called with the value
|
||||
/// true. When the sublist starts collapsing, this function is called with
|
||||
/// the value false.
|
||||
final ValueChanged<bool> onOpenChanged;
|
||||
|
||||
/// The widgets that are displayed when the sublist expands.
|
||||
///
|
||||
/// Typically [TwoLevelListItem] widgets.
|
||||
final List<Widget> children;
|
||||
|
||||
/// The color to display behind the sublist when expanded.
|
||||
final Color backgroundColor;
|
||||
|
||||
@override
|
||||
_TwoLevelSublistState createState() => _TwoLevelSublistState();
|
||||
}
|
||||
|
||||
@deprecated
|
||||
class _TwoLevelSublistState extends State<TwoLevelSublist> with SingleTickerProviderStateMixin {
|
||||
AnimationController _controller;
|
||||
CurvedAnimation _easeOutAnimation;
|
||||
CurvedAnimation _easeInAnimation;
|
||||
ColorTween _borderColor;
|
||||
ColorTween _headerColor;
|
||||
ColorTween _iconColor;
|
||||
ColorTween _backgroundColor;
|
||||
Animation<double> _iconTurns;
|
||||
|
||||
bool _isExpanded = false;
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
super.initState();
|
||||
_controller = AnimationController(duration: _kExpand, vsync: this);
|
||||
_easeOutAnimation = CurvedAnimation(parent: _controller, curve: Curves.easeOut);
|
||||
_easeInAnimation = CurvedAnimation(parent: _controller, curve: Curves.easeIn);
|
||||
_borderColor = ColorTween(begin: Colors.transparent);
|
||||
_headerColor = ColorTween();
|
||||
_iconColor = ColorTween();
|
||||
_iconTurns = Tween<double>(begin: 0.0, end: 0.5).animate(_easeInAnimation);
|
||||
_backgroundColor = ColorTween();
|
||||
|
||||
_isExpanded = PageStorage.of(context)?.readState(context) ?? false;
|
||||
if (_isExpanded)
|
||||
_controller.value = 1.0;
|
||||
}
|
||||
|
||||
@override
|
||||
void dispose() {
|
||||
_controller.dispose();
|
||||
super.dispose();
|
||||
}
|
||||
|
||||
void _handleOnTap() {
|
||||
setState(() {
|
||||
_isExpanded = !_isExpanded;
|
||||
if (_isExpanded)
|
||||
_controller.forward();
|
||||
else
|
||||
_controller.reverse();
|
||||
PageStorage.of(context)?.writeState(context, _isExpanded);
|
||||
});
|
||||
if (widget.onOpenChanged != null)
|
||||
widget.onOpenChanged(_isExpanded);
|
||||
}
|
||||
|
||||
Widget buildList(BuildContext context, Widget child) {
|
||||
return Container(
|
||||
decoration: BoxDecoration(
|
||||
color: _backgroundColor.evaluate(_easeOutAnimation),
|
||||
border: Border(
|
||||
top: BorderSide(color: _borderColor.evaluate(_easeOutAnimation)),
|
||||
bottom: BorderSide(color: _borderColor.evaluate(_easeOutAnimation))
|
||||
)
|
||||
),
|
||||
child: Column(
|
||||
children: <Widget>[
|
||||
IconTheme.merge(
|
||||
data: IconThemeData(color: _iconColor.evaluate(_easeInAnimation)),
|
||||
child: TwoLevelListItem(
|
||||
onTap: _handleOnTap,
|
||||
leading: widget.leading,
|
||||
title: DefaultTextStyle(
|
||||
style: Theme.of(context).textTheme.subhead.copyWith(color: _headerColor.evaluate(_easeInAnimation)),
|
||||
child: widget.title
|
||||
),
|
||||
trailing: RotationTransition(
|
||||
turns: _iconTurns,
|
||||
child: const Icon(Icons.expand_more)
|
||||
)
|
||||
)
|
||||
),
|
||||
ClipRect(
|
||||
child: Align(
|
||||
heightFactor: _easeInAnimation.value,
|
||||
child: Column(children: widget.children)
|
||||
)
|
||||
)
|
||||
]
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final ThemeData theme = Theme.of(context);
|
||||
_borderColor.end = theme.dividerColor;
|
||||
_headerColor
|
||||
..begin = theme.textTheme.subhead.color
|
||||
..end = theme.accentColor;
|
||||
_iconColor
|
||||
..begin = theme.unselectedWidgetColor
|
||||
..end = theme.accentColor;
|
||||
_backgroundColor
|
||||
..begin = Colors.transparent
|
||||
..end = widget.backgroundColor ?? Colors.transparent;
|
||||
|
||||
return AnimatedBuilder(
|
||||
animation: _controller.view,
|
||||
builder: buildList
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/// This class is deprecated. Please use [ListView] and [ListTileTheme] instead.
|
||||
@deprecated
|
||||
class TwoLevelList extends StatelessWidget {
|
||||
/// Creates a scrollable list of items that can expand and collapse.
|
||||
///
|
||||
/// The [type] argument must not be null.
|
||||
const TwoLevelList({
|
||||
Key key,
|
||||
this.children = const <Widget>[],
|
||||
this.type = MaterialListType.twoLine,
|
||||
this.padding,
|
||||
}) : assert(type != null),
|
||||
super(key: key);
|
||||
|
||||
/// The widgets to display in this list.
|
||||
///
|
||||
/// Typically [TwoLevelListItem] or [TwoLevelSublist] widgets.
|
||||
final List<Widget> children;
|
||||
|
||||
/// The kind of [ListTile] contained in this list.
|
||||
final MaterialListType type;
|
||||
|
||||
/// The amount of space by which to inset the children inside the viewport.
|
||||
final EdgeInsetsGeometry padding;
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return ListView(
|
||||
padding: padding,
|
||||
shrinkWrap: true,
|
||||
children: KeyedSubtree.ensureUniqueKeysForList(children),
|
||||
);
|
||||
}
|
||||
}
|
@ -1,135 +0,0 @@
|
||||
// Copyright 2016 The Chromium 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_test/flutter_test.dart';
|
||||
import 'package:flutter/widgets.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
|
||||
void main() {
|
||||
testWidgets('TwoLevelList basics', (WidgetTester tester) async {
|
||||
final Key topKey = UniqueKey();
|
||||
final Key sublistKey = UniqueKey();
|
||||
final Key bottomKey = UniqueKey();
|
||||
|
||||
final Map<String, WidgetBuilder> routes = <String, WidgetBuilder>{
|
||||
'/': (_) {
|
||||
return Material(
|
||||
child: SingleChildScrollView(
|
||||
child: Column(
|
||||
children: <Widget>[
|
||||
ListTile(title: const Text('Top'), key: topKey),
|
||||
ExpansionTile(
|
||||
key: sublistKey,
|
||||
title: const Text('Sublist'),
|
||||
children: const <Widget>[
|
||||
ListTile(title: Text('0')),
|
||||
ListTile(title: Text('1'))
|
||||
]
|
||||
),
|
||||
ListTile(title: const Text('Bottom'), key: bottomKey)
|
||||
]
|
||||
)
|
||||
)
|
||||
);
|
||||
}
|
||||
};
|
||||
|
||||
await tester.pumpWidget(MaterialApp(routes: routes));
|
||||
|
||||
expect(find.text('Top'), findsOneWidget);
|
||||
expect(find.text('Sublist'), findsOneWidget);
|
||||
expect(find.text('Bottom'), findsOneWidget);
|
||||
|
||||
double getY(Key key) => tester.getTopLeft(find.byKey(key)).dy;
|
||||
double getHeight(Key key) => tester.getSize(find.byKey(key)).height;
|
||||
|
||||
expect(getY(topKey), lessThan(getY(sublistKey)));
|
||||
expect(getY(sublistKey), lessThan(getY(bottomKey)));
|
||||
|
||||
// The sublist has a one pixel border above and below.
|
||||
expect(getHeight(topKey), equals(getHeight(sublistKey) - 2.0));
|
||||
expect(getHeight(bottomKey), equals(getHeight(sublistKey) - 2.0));
|
||||
|
||||
await tester.tap(find.text('Sublist'));
|
||||
await tester.pump(const Duration(seconds: 1));
|
||||
await tester.pump(const Duration(seconds: 1));
|
||||
|
||||
expect(find.text('Top'), findsOneWidget);
|
||||
expect(find.text('Sublist'), findsOneWidget);
|
||||
expect(find.text('0'), findsOneWidget);
|
||||
expect(find.text('1'), findsOneWidget);
|
||||
expect(find.text('Bottom'), findsOneWidget);
|
||||
|
||||
expect(getY(topKey), lessThan(getY(sublistKey)));
|
||||
expect(getY(sublistKey), lessThan(getY(bottomKey)));
|
||||
expect(getY(bottomKey) - getY(sublistKey), greaterThan(getHeight(topKey)));
|
||||
expect(getY(bottomKey) - getY(sublistKey), greaterThan(getHeight(bottomKey)));
|
||||
});
|
||||
|
||||
testWidgets('onExpansionChanged callback', (WidgetTester tester) async {
|
||||
bool didChangeOpen;
|
||||
|
||||
final Map<String, WidgetBuilder> routes = <String, WidgetBuilder>{
|
||||
'/': (_) {
|
||||
return Material(
|
||||
child: SingleChildScrollView(
|
||||
child: Column(
|
||||
children: <Widget>[
|
||||
ExpansionTile(
|
||||
title: const Text('Sublist'),
|
||||
onExpansionChanged: (bool opened) {
|
||||
didChangeOpen = opened;
|
||||
},
|
||||
children: const <Widget>[
|
||||
ListTile(title: Text('0')),
|
||||
ListTile(title: Text('1'))
|
||||
]
|
||||
),
|
||||
]
|
||||
)
|
||||
)
|
||||
);
|
||||
}
|
||||
};
|
||||
|
||||
await tester.pumpWidget(MaterialApp(routes: routes));
|
||||
|
||||
expect(didChangeOpen, isNull);
|
||||
await tester.tap(find.text('Sublist'));
|
||||
expect(didChangeOpen, isTrue);
|
||||
await tester.pump();
|
||||
await tester.pump(const Duration(seconds: 1));
|
||||
await tester.tap(find.text('Sublist'));
|
||||
expect(didChangeOpen, isFalse);
|
||||
});
|
||||
|
||||
testWidgets('trailing override', (WidgetTester tester) async {
|
||||
final Map<String, WidgetBuilder> routes = <String, WidgetBuilder>{
|
||||
'/': (_) {
|
||||
return Material(
|
||||
child: SingleChildScrollView(
|
||||
child: Column(
|
||||
children: const <Widget>[
|
||||
ListTile(title: Text('Top')),
|
||||
ExpansionTile(
|
||||
title: Text('Sublist'),
|
||||
children: <Widget>[
|
||||
ListTile(title: Text('0')),
|
||||
ListTile(title: Text('1'))
|
||||
],
|
||||
trailing: Icon(Icons.inbox),
|
||||
),
|
||||
ListTile(title: Text('Bottom'))
|
||||
]
|
||||
)
|
||||
)
|
||||
);
|
||||
}
|
||||
};
|
||||
|
||||
await tester.pumpWidget(MaterialApp(routes: routes));
|
||||
expect(find.byIcon(Icons.inbox), findsOneWidget);
|
||||
expect(find.byIcon(Icons.expand_more), findsNothing);
|
||||
});
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user