using System; using System.Collections.Generic; using uiwidgets; using Unity.UIWidgets.animation; using Unity.UIWidgets.foundation; using Unity.UIWidgets.painting; using Unity.UIWidgets.rendering; using Unity.UIWidgets.ui; using Unity.UIWidgets.widgets; namespace Unity.UIWidgets.material { static class ExpansionTileUtils { public static readonly TimeSpan _kExpand = new TimeSpan(0, 0, 0, 0, 200); } public class ExpansionTile : StatefulWidget { public ExpansionTile( Key key = null, Widget leading = null, Widget title = null, Widget subtitle = null, Color backgroundColor = null, ValueChanged onExpansionChanged = null, List children = null, Widget trailing = null, bool initiallyExpanded = false ) : base(key: key) { D.assert(title != null); this.leading = leading; this.title = title; this.subtitle = subtitle; this.backgroundColor = backgroundColor; this.onExpansionChanged = onExpansionChanged; this.children = children ?? new List(); this.trailing = trailing; this.initiallyExpanded = initiallyExpanded; } public readonly Widget leading; public readonly Widget title; public readonly Widget subtitle; public readonly ValueChanged onExpansionChanged; public readonly List children; public readonly Color backgroundColor; public readonly Widget trailing; public readonly bool initiallyExpanded; public override State createState() { return new _ExpansionTileState(); } } public class _ExpansionTileState : SingleTickerProviderStateMixin { static readonly Animatable _easeOutTween = new CurveTween(curve: Curves.easeOut); static readonly Animatable _easeInTween = new CurveTween(curve: Curves.easeIn); static readonly Animatable _halfTween = new FloatTween(begin: 0.0f, end: 0.5f); readonly ColorTween _borderColorTween = new ColorTween(); readonly ColorTween _headerColorTween = new ColorTween(); readonly ColorTween _iconColorTween = new ColorTween(); readonly ColorTween _backgroundColorTween = new ColorTween(); AnimationController _controller; Animation _iconTurns; Animation _heightFactor; Animation _borderColor; Animation _headerColor; Animation _iconColor; Animation _backgroundColor; bool _isExpanded = false; public override void initState() { base.initState(); _controller = new AnimationController(duration: ExpansionTileUtils._kExpand, vsync: this); _heightFactor = _controller.drive(_easeInTween); _iconTurns = _controller.drive(_halfTween.chain(_easeInTween)); _borderColor = _controller.drive(_borderColorTween.chain(_easeOutTween)); _headerColor = _controller.drive(_headerColorTween.chain(_easeInTween)); _iconColor = _controller.drive(_iconColorTween.chain(_easeInTween)); _backgroundColor = _controller.drive(_backgroundColorTween.chain(_easeOutTween)); _isExpanded = PageStorage.of(context)?.readState(context) == null ? widget.initiallyExpanded : (bool) PageStorage.of(context)?.readState(context); if (_isExpanded) { _controller.setValue(1.0f); } } public override void dispose() { _controller.dispose(); base.dispose(); } void _handleTap() { setState(() => { _isExpanded = !_isExpanded; if (_isExpanded) { _controller.forward(); } else { _controller.reverse().then((value) => { if (!mounted) { return; } setState(() => { }); }); } PageStorage.of(context)?.writeState(context, _isExpanded); }); if (widget.onExpansionChanged != null) { widget.onExpansionChanged(_isExpanded); } } Widget _buildChildren(BuildContext context, Widget child) { Color borderSideColor = _borderColor.value ?? Colors.transparent; return new Container( decoration: new BoxDecoration( color: _backgroundColor.value ?? Colors.transparent, border: new Border( top: new BorderSide(color: borderSideColor), bottom: new BorderSide(color: borderSideColor))), child: new Column( mainAxisSize: MainAxisSize.min, children: new List { ListTileTheme.merge( iconColor: _iconColor.value, textColor: _headerColor.value, child: new ListTile( onTap: _handleTap, leading: widget.leading, title: widget.title, subtitle: widget.subtitle, trailing: widget.trailing ?? new RotationTransition( turns: _iconTurns, child: new Icon(Icons.expand_more) ) ) ), new ClipRect( child: new Align( heightFactor: _heightFactor.value, child: child) ) } ) ); } public override void didChangeDependencies() { ThemeData theme = Theme.of(context); _borderColorTween.end = theme.dividerColor; _headerColorTween.begin = theme.textTheme.subtitle1.color; _headerColorTween.end = theme.accentColor; _iconColorTween.begin = theme.unselectedWidgetColor; _iconColorTween.end = theme.accentColor; _backgroundColorTween.end = widget.backgroundColor; base.didChangeDependencies(); } public override Widget build(BuildContext context) { bool closed = !_isExpanded && _controller.isDismissed; return new AnimatedBuilder( animation: _controller.view, builder: _buildChildren, child: closed ? null : new Column(children: widget.children)); } } }