add IconToggle

master
lmy 5 years ago
parent db9a267767
commit 4e74c20352

@ -14,3 +14,4 @@ export 'zocial.dart';
export 'foundation.dart';
export 'font_awesome_5.dart';
export 'flutter_icon_data.dart' show IconWeight;
export 'icon_toggle.dart';

@ -0,0 +1,143 @@
///
///
/// bool
///
///
import 'package:flutter/material.dart';
import 'dart:math' as math;
Widget _defaultTransitionBuilder(Widget child, Animation<double> animation) =>
ScaleTransition(
scale: animation,
child: child,
);
class IconToggle extends StatefulWidget {
IconToggle({
this.uncheckedIconData = Icons.radio_button_unchecked,
this.checkedIconData = Icons.radio_button_checked,
this.activeColor = Colors.blue,
this.inactiveColor = Colors.grey,
this.value = false,
this.onChanged,
this.transitionBuilder = _defaultTransitionBuilder,
this.duration = const Duration(milliseconds: 100),
this.reverseDuration,
});
final IconData checkedIconData;
final IconData uncheckedIconData;
final Color activeColor;
final Color inactiveColor;
final bool value;
final ValueChanged<bool> onChanged;
final AnimatedSwitcherTransitionBuilder transitionBuilder;
final Duration duration;
final Duration reverseDuration;
@override
_IconToggleState createState() => _IconToggleState();
}
class _IconToggleState extends State<IconToggle>
with SingleTickerProviderStateMixin {
AnimationController _controller;
Animation<double> _position;
@override
void initState() {
super.initState();
_controller = AnimationController(
vsync: this,
duration: Duration(milliseconds: 100),
reverseDuration: Duration(milliseconds: 50));
_position = CurvedAnimation(parent: _controller, curve: Curves.linear);
_position.addStatusListener((status) {
if (status == AnimationStatus.dismissed && widget.onChanged != null) {
widget.onChanged(!widget.value);
}
});
}
@override
void dispose() {
_controller?.dispose();
super.dispose();
}
@override
Widget build(BuildContext context) {
return GestureDetector(
onTapDown: (event) {
_controller?.forward();
},
onTapUp: (event) {
_controller?.reverse();
},
child: _IconToggleable<double>(
listenable: _position,
activeColor: widget.activeColor,
inactiveColor: widget.inactiveColor,
child: AnimatedSwitcher(
duration: widget.duration,
reverseDuration: widget.reverseDuration,
transitionBuilder: widget.transitionBuilder,
child: Icon(
widget.value ? widget.checkedIconData : widget.uncheckedIconData,
color: widget.value ? widget.activeColor : widget.inactiveColor,
size: 22,
key: ValueKey<bool>(widget.value),
),
),
),
);
}
}
class _IconToggleable<T> extends AnimatedWidget {
_IconToggleable({
Animation<T> listenable,
this.activeColor,
this.inactiveColor,
this.child,
}) : super(listenable: listenable);
final Color activeColor;
final Color inactiveColor;
final Widget child;
@override
Widget build(BuildContext context) {
return CustomPaint(
painter: _IconPainter(
position: listenable,
activeColor: activeColor,
inactiveColor: inactiveColor,
),
child: child,
);
}
}
class _IconPainter extends CustomPainter {
_IconPainter({
@required this.position,
this.activeColor,
this.inactiveColor,
});
final Animation<double> position;
final Color activeColor;
final Color inactiveColor;
double get _value => position != null ? position.value : 0;
@override
void paint(Canvas canvas, Size size) {
final Paint paint = Paint()
..color = Color.lerp(inactiveColor, activeColor, _value)
.withOpacity(math.min(_value, 0.1))
..style = PaintingStyle.fill
..strokeWidth = 2.0;
canvas.drawCircle(
Offset(size.width / 2, size.height / 2), 20 * _value, paint);
}
@override
bool shouldRepaint(CustomPainter oldDelegate) => true;
}
Loading…
Cancel
Save