parent
db9a267767
commit
4e74c20352
@ -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…
Reference in new issue