You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
144 lines
3.8 KiB
144 lines
3.8 KiB
6 years ago
|
///
|
||
|
///
|
||
|
/// 自定义的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;
|
||
|
}
|