Inject color into the ExpansionCard
This commit is contained in:
parent
16a7e5d67f
commit
5bab89b493
2 changed files with 276 additions and 28 deletions
231
lib/ui/expansion_card.dart
Normal file
231
lib/ui/expansion_card.dart
Normal file
|
@ -0,0 +1,231 @@
|
|||
import 'package:flutter/widgets.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
|
||||
const Duration _kExpand = Duration(milliseconds: 200);
|
||||
|
||||
/// A single-line [ListTile] with a trailing button that expands or collapses
|
||||
/// the tile to reveal or hide the [children].
|
||||
///
|
||||
/// This widget is typically used with [ListView] to create an
|
||||
/// "expand / collapse" list entry. When used with scrolling widgets like
|
||||
/// [ListView], a unique [PageStorageKey] must be specified to enable the
|
||||
/// [ExpansionTile] to save and restore its expanded state when it is scrolled
|
||||
/// in and out of view.
|
||||
///
|
||||
/// See also:
|
||||
///
|
||||
/// * [ListTile], useful for creating expansion tile [children] when the
|
||||
/// expansion tile represents a sublist.
|
||||
/// * The "Expand/collapse" section of
|
||||
/// <https://material.io/guidelines/components/lists-controls.html>.
|
||||
class ExpansionCard extends StatefulWidget {
|
||||
/// Creates a single-line [ListTile] with a trailing button that expands or collapses
|
||||
/// the tile to reveal or hide the [children]. The [initiallyExpanded] property must
|
||||
/// be non-null.
|
||||
const ExpansionCard({
|
||||
Key key,
|
||||
this.leading,
|
||||
@required this.title,
|
||||
this.background,
|
||||
this.backgroundColor,
|
||||
this.margin = const EdgeInsets.only(top: 30),
|
||||
this.borderRadius = 30.0,
|
||||
this.onExpansionChanged,
|
||||
this.children = const <Widget>[],
|
||||
this.trailing,
|
||||
this.initiallyExpanded = false,
|
||||
this.color,
|
||||
}) : assert(initiallyExpanded != null),
|
||||
super(key: key);
|
||||
|
||||
/// Adds margin to content of the card.
|
||||
final EdgeInsets margin;
|
||||
|
||||
/// Provides CircularRadius to the border of the card.
|
||||
final double borderRadius;
|
||||
|
||||
/// A widget to add background.
|
||||
/// it can be a gif or image.
|
||||
final Widget background;
|
||||
|
||||
/// 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 tile expands or collapses.
|
||||
///
|
||||
/// When the tile starts expanding, this function is called with the value
|
||||
/// true. When the tile starts collapsing, this function is called with
|
||||
/// the value false.
|
||||
final ValueChanged<bool> onExpansionChanged;
|
||||
|
||||
/// The widgets that are displayed when the tile expands.
|
||||
///
|
||||
/// Typically [ListTile] widgets.
|
||||
final List<Widget> children;
|
||||
|
||||
/// The color to display behind the sublist when expanded.
|
||||
final Color backgroundColor;
|
||||
|
||||
/// A widget to display instead of a rotating arrow icon.
|
||||
final Widget trailing;
|
||||
|
||||
/// Specifies if the list tile is initially expanded (true) or collapsed (false, the default).
|
||||
final bool initiallyExpanded;
|
||||
|
||||
/// Color of the expanded heading and icon
|
||||
final Color color;
|
||||
|
||||
@override
|
||||
_ExpansionTileState createState() => _ExpansionTileState();
|
||||
}
|
||||
|
||||
class _ExpansionTileState extends State<ExpansionCard>
|
||||
with SingleTickerProviderStateMixin {
|
||||
static final Animatable<double> _easeOutTween =
|
||||
CurveTween(curve: Curves.easeOut);
|
||||
static final Animatable<double> _easeInTween =
|
||||
CurveTween(curve: Curves.easeIn);
|
||||
static final Animatable<double> _halfTween =
|
||||
Tween<double>(begin: 0.0, end: 0.5);
|
||||
|
||||
final ColorTween _borderColorTween = ColorTween();
|
||||
final ColorTween _headerColorTween = ColorTween();
|
||||
final ColorTween _iconColorTween = ColorTween();
|
||||
final ColorTween _backgroundColorTween = ColorTween();
|
||||
|
||||
AnimationController _controller;
|
||||
Animation<double> _iconTurns;
|
||||
Animation<double> _heightFactor;
|
||||
Animation<Color> _headerColor;
|
||||
Animation<Color> _iconColor;
|
||||
Animation<Color> _backgroundColor;
|
||||
|
||||
bool _isExpanded = false;
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
super.initState();
|
||||
_controller = AnimationController(duration: _kExpand, vsync: this);
|
||||
_heightFactor = _controller.drive(_easeInTween);
|
||||
_iconTurns = _controller.drive(_halfTween.chain(_easeInTween));
|
||||
_headerColor = _controller.drive(_headerColorTween.chain(_easeInTween));
|
||||
_iconColor = _controller.drive(_iconColorTween.chain(_easeInTween));
|
||||
_backgroundColor =
|
||||
_controller.drive(_backgroundColorTween.chain(_easeOutTween));
|
||||
|
||||
_isExpanded =
|
||||
PageStorage.of(context)?.readState(context) ?? widget.initiallyExpanded;
|
||||
if (_isExpanded) _controller.value = 1.0;
|
||||
}
|
||||
|
||||
@override
|
||||
void dispose() {
|
||||
_controller.dispose();
|
||||
super.dispose();
|
||||
}
|
||||
|
||||
void _handleTap() {
|
||||
setState(() {
|
||||
_isExpanded = !_isExpanded;
|
||||
if (_isExpanded) {
|
||||
_controller.forward();
|
||||
} else {
|
||||
_controller.reverse().then<void>((void value) {
|
||||
if (!mounted) return;
|
||||
setState(() {
|
||||
// Rebuild without widget.children.
|
||||
});
|
||||
});
|
||||
}
|
||||
PageStorage.of(context)?.writeState(context, _isExpanded);
|
||||
});
|
||||
if (widget.onExpansionChanged != null)
|
||||
widget.onExpansionChanged(_isExpanded);
|
||||
}
|
||||
|
||||
Widget _buildChildren(BuildContext context, Widget child) {
|
||||
final Color borderSideColor = Colors.transparent; // _borderColor.value ??
|
||||
|
||||
return Stack(
|
||||
children: <Widget>[
|
||||
widget.background == null
|
||||
? Container()
|
||||
: ClipRRect(
|
||||
borderRadius: BorderRadius.circular(widget.borderRadius),
|
||||
child: Align(
|
||||
heightFactor:
|
||||
_heightFactor.value < 0.5 ? 0.5 : _heightFactor.value,
|
||||
child: widget.background,
|
||||
),
|
||||
),
|
||||
Container(
|
||||
decoration: BoxDecoration(
|
||||
color: _backgroundColor.value ?? Colors.transparent,
|
||||
border: Border(
|
||||
top: BorderSide(color: borderSideColor),
|
||||
bottom: BorderSide(color: borderSideColor),
|
||||
),
|
||||
),
|
||||
child: Column(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: <Widget>[
|
||||
ListTileTheme.merge(
|
||||
iconColor: _iconColor.value,
|
||||
textColor: _headerColor.value,
|
||||
child: Container(
|
||||
margin: widget.margin,
|
||||
child: ListTile(
|
||||
onTap: _handleTap,
|
||||
leading: widget.leading,
|
||||
title: widget.title,
|
||||
trailing: widget.trailing ??
|
||||
RotationTransition(
|
||||
turns: _iconTurns,
|
||||
child: const Icon(Icons.expand_more),
|
||||
),
|
||||
),
|
||||
)),
|
||||
ClipRect(
|
||||
child: Align(
|
||||
heightFactor: _heightFactor.value,
|
||||
child: child,
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
)
|
||||
],
|
||||
);
|
||||
}
|
||||
|
||||
@override
|
||||
void didChangeDependencies() {
|
||||
final ThemeData theme = Theme.of(context);
|
||||
_borderColorTween..end = theme.dividerColor;
|
||||
_headerColorTween
|
||||
..begin = Colors.white
|
||||
..end = widget.color ?? Color(0xff60c9df);
|
||||
_iconColorTween
|
||||
..begin = Colors.white
|
||||
..end = widget.color ?? Color(0xff60c9df);
|
||||
_backgroundColorTween..end = widget.backgroundColor;
|
||||
super.didChangeDependencies();
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final bool closed = !_isExpanded && _controller.isDismissed;
|
||||
return AnimatedBuilder(
|
||||
animation: _controller.view,
|
||||
builder: _buildChildren,
|
||||
child: closed ? null : Column(children: widget.children),
|
||||
);
|
||||
}
|
||||
}
|
|
@ -2,13 +2,12 @@ import 'dart:async';
|
|||
import 'dart:convert';
|
||||
import 'dart:io';
|
||||
|
||||
import 'package:expansion_card/expansion_card.dart';
|
||||
import 'package:flutter/cupertino.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter/widgets.dart';
|
||||
import 'package:flutter_inappwebview/flutter_inappwebview.dart';
|
||||
import 'package:in_app_purchase/in_app_purchase.dart';
|
||||
import 'package:logging/logging.dart';
|
||||
import 'package:photos/ui/expansion_card.dart';
|
||||
import 'package:progress_dialog/progress_dialog.dart';
|
||||
import 'package:url_launcher/url_launcher.dart';
|
||||
|
||||
|
@ -296,20 +295,24 @@ class _SubscriptionPageState extends State<SubscriptionPage> {
|
|||
),
|
||||
]);
|
||||
} else {
|
||||
widgets.addAll([
|
||||
Align(
|
||||
alignment: Alignment.topLeft,
|
||||
child: Padding(
|
||||
padding: EdgeInsets.all(12),
|
||||
child: Text(
|
||||
"we offer a 14 day free trial, you can cancel anytime",
|
||||
style: TextStyle(
|
||||
color: Colors.white,
|
||||
height: 1.2,
|
||||
if (_currentSubscription == null) {
|
||||
widgets.addAll([
|
||||
Align(
|
||||
alignment: Alignment.topLeft,
|
||||
child: Padding(
|
||||
padding: EdgeInsets.all(12),
|
||||
child: Text(
|
||||
"we offer a 14 day free trial, you can cancel anytime",
|
||||
style: TextStyle(
|
||||
color: Colors.white,
|
||||
height: 1.2,
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
]);
|
||||
}
|
||||
widgets.addAll([
|
||||
Expanded(child: Container()),
|
||||
Align(
|
||||
alignment: Alignment.center,
|
||||
|
@ -390,21 +393,7 @@ class _BillingQuestionsWidgetState extends State<BillingQuestionsWidget> {
|
|||
),
|
||||
));
|
||||
for (final faq in snapshot.data) {
|
||||
faqs.add(ExpansionCard(
|
||||
margin: EdgeInsets.only(bottom: 2),
|
||||
title: Text(faq.q),
|
||||
children: [
|
||||
Padding(
|
||||
padding: const EdgeInsets.only(left: 16, right: 16),
|
||||
child: Text(
|
||||
faq.a,
|
||||
style: TextStyle(
|
||||
height: 1.5,
|
||||
),
|
||||
),
|
||||
)
|
||||
],
|
||||
));
|
||||
faqs.add(FaqWidget(faq: faq));
|
||||
}
|
||||
faqs.add(Padding(
|
||||
padding: EdgeInsets.all(16),
|
||||
|
@ -424,6 +413,34 @@ class _BillingQuestionsWidgetState extends State<BillingQuestionsWidget> {
|
|||
}
|
||||
}
|
||||
|
||||
class FaqWidget extends StatelessWidget {
|
||||
const FaqWidget({
|
||||
Key key,
|
||||
@required this.faq,
|
||||
}) : super(key: key);
|
||||
|
||||
final faq;
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return ExpansionCard(
|
||||
title: Text(faq.q),
|
||||
color: Theme.of(context).accentColor,
|
||||
children: [
|
||||
Padding(
|
||||
padding: const EdgeInsets.only(left: 16, right: 16),
|
||||
child: Text(
|
||||
faq.a,
|
||||
style: TextStyle(
|
||||
height: 1.5,
|
||||
),
|
||||
),
|
||||
)
|
||||
],
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
class FaqItem {
|
||||
final String q;
|
||||
final String a;
|
||||
|
|
Loading…
Add table
Reference in a new issue