Commit 7bd4b5a9 authored by Dragoș Tiselice's avatar Dragoș Tiselice Committed by GitHub

Added ExpandIcon widget. (#5463)

Added a widget that automaitcally rotates the expansion icon and
offers a callback interface that captures presses.
parent 77a1719c
......@@ -34,6 +34,7 @@ export 'src/material/drawer.dart';
export 'src/material/drawer_header.dart';
export 'src/material/drawer_item.dart';
export 'src/material/drop_down.dart';
export 'src/material/expand_icon.dart';
export 'src/material/flat_button.dart';
export 'src/material/flexible_space_bar.dart';
export 'src/material/floating_action_button.dart';
......
// Copyright 2015 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 'package:meta/meta.dart';
import 'colors.dart';
import 'debug.dart';
import 'icon.dart';
import 'icons.dart';
import 'icon_button.dart';
import 'theme.dart';
/// A widget representing a rotating expand/collapse button. The icon rotates
/// 180 deg when pressed, then reverts the animation on a second press.
/// The underlying icon is [Icons.expand_more].
///
/// See [IconButton] for a more general implementation of a pressable button
/// with an icon.
class ExpandIcon extends StatefulWidget {
/// Creates an [ExpandIcon] with the given padding, and a callback that is
/// triggered when the icon is pressed.
ExpandIcon({
Key key,
this.size: 24.0,
@required this.onPressed,
this.padding: const EdgeInsets.all(8.0)
}) : super(key: key) {
assert(this.size != null);
assert(this.padding != null);
}
/// The size of the icon.
///
/// This property must not be null. It defaults to 24.0.
final double size;
/// The callback triggered when the icon is pressed and the state changes
/// between expanded and collapsed.
///
/// If this is set to null, the button will be disabled.
final ValueChanged<bool> onPressed;
/// The padding around the icon. The entire padded icon will reactb to input
/// gestures.
///
/// This property must not be null. It defaults to 8.0 padding on all sides.
final EdgeInsets padding;
@override
_ExpandIconState createState() => new _ExpandIconState();
}
class _ExpandIconState extends State<ExpandIcon> {
AnimationController _controller;
Animation<double> _iconTurns;
bool _isExpanded = false;
@override
void initState() {
super.initState();
_controller = new AnimationController(duration: kThemeAnimationDuration);
_iconTurns = new Tween<double>(begin: 0.0, end: 0.5).animate(
new CurvedAnimation(
parent: _controller,
curve: Curves.fastOutSlowIn
)
);
}
@override
void dispose() {
_controller.dispose();
super.dispose();
}
void _handlePressed() {
setState(() {
_isExpanded = !_isExpanded;
if (_isExpanded)
_controller.forward();
else
_controller.reverse();
});
if (config.onPressed != null)
config.onPressed(_isExpanded);
}
@override
Widget build(BuildContext context) {
assert(debugCheckHasMaterial(context));
return new IconButton(
padding: config.padding,
color: Colors.black38,
onPressed: config.onPressed == null ? null : _handlePressed,
icon: new RotationTransition(
turns: _iconTurns,
child: new Icon(Icons.expand_more)
)
);
}
}
// 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/material.dart';
import 'package:flutter_test/flutter_test.dart';
void main() {
testWidgets('ExpandIcon test', (WidgetTester tester) async {
bool expanded = false;
await tester.pumpWidget(
new Material(
child: new Center(
child: new ExpandIcon(
onPressed: (bool isExpanded) {
expanded = !expanded;
}
)
)
)
);
expect(expanded, isFalse);
await tester.tap(find.byType(ExpandIcon));
expect(expanded, isTrue);
await tester.pump(const Duration(milliseconds: 100));
await tester.tap(find.byType(ExpandIcon));
expect(expanded, isFalse);
});
testWidgets('ExpandIcon disabled', (WidgetTester tester) async {
await tester.pumpWidget(
new Material(
child: new Center(
child: new ExpandIcon(
onPressed: null
)
)
)
);
IconTheme iconTheme = tester.firstWidget(find.byType(IconTheme));
expect(iconTheme.data.color, equals(Colors.black26));
});
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment