blob: 9f32ef6eecbcb6e7c222ffd5808c1cef50d5ca98 [file] [log] [blame]
// 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/foundation.dart';
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 = const 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 new SizedBox(
height: kListTileExtent[parentList.type],
child: new 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 expland 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() => new _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 = new AnimationController(duration: _kExpand, vsync: this);
_easeOutAnimation = new CurvedAnimation(parent: _controller, curve: Curves.easeOut);
_easeInAnimation = new CurvedAnimation(parent: _controller, curve: Curves.easeIn);
_borderColor = new ColorTween(begin: Colors.transparent);
_headerColor = new ColorTween();
_iconColor = new ColorTween();
_iconTurns = new Tween<double>(begin: 0.0, end: 0.5).animate(_easeInAnimation);
_backgroundColor = new 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 new Container(
decoration: new BoxDecoration(
color: _backgroundColor.evaluate(_easeOutAnimation),
border: new Border(
top: new BorderSide(color: _borderColor.evaluate(_easeOutAnimation)),
bottom: new BorderSide(color: _borderColor.evaluate(_easeOutAnimation))
)
),
child: new Column(
children: <Widget>[
IconTheme.merge(
data: new IconThemeData(color: _iconColor.evaluate(_easeInAnimation)),
child: new TwoLevelListItem(
onTap: _handleOnTap,
leading: widget.leading,
title: new DefaultTextStyle(
style: Theme.of(context).textTheme.subhead.copyWith(color: _headerColor.evaluate(_easeInAnimation)),
child: widget.title
),
trailing: new RotationTransition(
turns: _iconTurns,
child: const Icon(Icons.expand_more)
)
)
),
new ClipRect(
child: new Align(
heightFactor: _easeInAnimation.value,
child: new 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 new 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 EdgeInsets padding;
@override
Widget build(BuildContext context) {
return new ListView(
padding: padding,
shrinkWrap: true,
children: KeyedSubtree.ensureUniqueKeysForList(children),
);
}
}