人生,就是要不断的折腾。没有折腾的人生是不完美的人生。--- 鲁迅
哈哈,当然鲁迅一定会沉下脸来,大声道:“劳资没说过!”
昨天折腾了下CircleProgressBar组件,今天觉得不过瘾,继续折腾了一个新的组件:SwitchButton。真是不容易,现在最恼火的是没有找到办法精确的去处理SwitchButton的点击事件。如果亲爱的Reader有办法,麻烦你们不吝赐教,小弟在此先谢了。
还是先上Demo效果图吧!
项目地址:https://gitee.com/yugecse/Switch-Button
- 构建SwitchButton的Lerp函数及类
class SwitchButtonLerp {
SwitchButtonLerp({this.isOpen = false, this.fraction});
bool isOpen;
double fraction;
static SwitchButtonLerp lerp(
SwitchButtonLerp begin, SwitchButtonLerp end, double fraction) =>
new SwitchButtonLerp(
fraction: lerpDouble(begin.fraction, end.fraction, fraction));
}
- SwitchButton类
class SwitchButton extends StatefulWidget {
SwitchButton(
{Key key, this.size = const Size(50.0, 30.0), this.isOpen = true})
: super(key: key);
Size size;
bool isOpen;
@override
State createState() => new _SwitchButtonState();
}
class _SwitchButtonState extends State<SwitchButton>
with TickerProviderStateMixin {
AnimationController animationController;
SwitchButtonTween switchButtonTween;
void _tap(PointerDownEvent event) {
final radius = widget.size.height / 2.0;
final circleCenter = new Offset(widget.isOpen ? widget.size.width - radius : radius, radius);
print("坐标信息:$circleCenter, ${event.position}");
setState(() {
widget.isOpen = !widget.isOpen;
print("=======>changed!");
});
//以下代码可以暂时注释,因为没用上
if(_isInCircle(radius, circleCenter, event.position)){
//判断用户是否点击在小圆上,暂未找到解决办法。event.position是针对屏幕的坐标位置
}else {
print("-------->区域外点击");
}
}
///
/// 判断某个点是否在圆内及圆上
/// radius 圆半径
/// circleCenter 圆心坐标
/// point 目标点
///
bool _isInCircle(double radius, Offset circleCenter, Offset point) =>
pow(point.dx - circleCenter.dx, 2) + pow(point.dy - circleCenter.dy, 2) <=
pow(radius, 2);
@override
Widget build(BuildContext context) {
setState(() {
animationController = new AnimationController(
vsync: this, duration: new Duration(milliseconds: 300));
switchButtonTween = new SwitchButtonTween(
new SwitchButtonLerp(
isOpen: widget.isOpen, fraction: widget.isOpen ? 0.0 : 1.0),
new SwitchButtonLerp(
isOpen: widget.isOpen, fraction: widget.isOpen ? 1.0 : 0.0));
animationController.forward();
});
return new Listener(
onPointerDown: _tap,
child: new CustomPaint(
size: widget.size,
painter: new SwitchButtonPainter(
switchButtonTween.animate(animationController)),
),
);
}
}
- SwitchButtonPainter类,绘制Switch-Button图形。
class SwitchButtonTween extends Tween<SwitchButtonLerp> {
SwitchButtonTween(SwitchButtonLerp begin, SwitchButtonLerp end)
: super(begin: begin, end: end);
@override
SwitchButtonLerp lerp(double fraction) => SwitchButtonLerp.lerp(begin, end, fraction);
}
class SwitchButtonPainter extends CustomPainter {
SwitchButtonPainter(Animation<SwitchButtonLerp> animation)
: animation = animation,
super(repaint: animation);
Animation<SwitchButtonLerp> animation;
@override
void paint(Canvas canvas, Size size) {
final double animationValue = animation.value.fraction;
final bool openState = animation.value.isOpen;
final paint = Paint()
..color = openState ? Colors.green : Colors.grey[400]
..style = PaintingStyle.fill;
final path = Path();
final pRadius = size.height / 2.0;
for (double a = 0.0; a < 360.0; a += 0.001) { //利用数学公式计算在圆边上的点的坐标,半圆图形
double x = pRadius + pRadius * cos(a * pi / 180.0);
double y = pRadius + pRadius * sin(a * pi / 180.0);
if (a != 0.0)
path.lineTo(x, y);
else
path.moveTo(x, y);
}
path.addRect( //绘制矩形
new Rect.fromLTWH(pRadius, 0.0, size.width - 2 * pRadius, size.height));
for (double a = 0.0; a < 360.0; a += 0.001) { //利用数学公式计算在圆边上的点的坐标,半圆图形
double x =
size.width - 2 * pRadius + pRadius + pRadius * cos(a * pi / 180.0);
double y = pRadius + pRadius * sin(a * pi / 180.0);
if (a != 0.0)
path.lineTo(x, y);
else
path.moveTo(x, y);
}
path.close();
canvas.drawPath(path, paint);
paint.color = Colors.white70;
canvas.drawCircle( //绘制动圆,根据动画值处理动圆的x坐标
new Offset(
pRadius + animationValue * (size.width - 2 * pRadius), pRadius),
pRadius,
paint);
}
@override
bool shouldRepaint(CustomPainter oldDelegate) => false;
}
测试类
void main() => runApp(new MyApp());
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return new MaterialApp(
title: 'Flutter Demo',
theme: new ThemeData(
primarySwatch: Colors.blue,
),
home: new MyHomePage(title: 'Flutter Demo Home Page'),
);
}
}
class MyHomePage extends StatefulWidget {
MyHomePage({Key key, this.title}) : super(key: key);
final String title;
@override
_MyHomePageState createState() => new _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
int _counter = 0;
bool isSwitchButtonOpen = true;
void _incrementCounter() {
setState(() {
_counter++;
});
}
void _switchState() {
setState(() {
this.isSwitchButtonOpen = !this.isSwitchButtonOpen;
print("======> 状态变化了: ${this.isSwitchButtonOpen}");
});
}
@override
Widget build(BuildContext context) {
return new Scaffold(
appBar: new AppBar(
title: new Text(widget.title),
),
body: new Center(
child: new Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
new SwitchButton(
isOpen: isSwitchButtonOpen,
size: new Size(50.0, 28.0),
),
new RaisedButton(
onPressed: _switchState,
child: new Text("点我啊!"),
),
new Text(
'You have pushed the button this many times:',
),
new Text(
'$_counter',
style: Theme.of(context).textTheme.display1,
),
],
),
),
floatingActionButton: new FloatingActionButton(
onPressed: _incrementCounter,
tooltip: 'Increment',
child: new Icon(Icons.add),
),
);
}
}
现存问题
目前最蛋疼的问题是怎么去处理精确点击。。。