(点击
上方公众号
,可快速关注)
来源:伯乐在线专栏作者 - Code4Android
链接:http://android.jobbole.com/84776/
点击 → 了解如何加入专栏作者
接上文
通过效果图,我们看到实现此效果就是不断的更新进度值,然后重绘,,那么我们只需开启一个线程实现更新进度值,为了更好的控制我们再加点击事件,当单机时开始增大进度,双击时暂停进度,并弹出Snackbar,其中有一个重置按钮,点击重置时将进度设置为0,重绘界面。
响应点击事件
因为要实现双击事件,我们可以直接用GestureDetector(手势检测),通过这个类我们可以识别很多的手势,主要是通过他的onTouchEvent(event)方法完成了不同手势的识别GestureDetector里有一个内部类 SimpleOnGestureListener。SimpleOnGestureListener类是GestureDetector提供给我们的一个更方便的响应不同手势的类,这个类实现了上述两个接口(OnGestureListener, OnDoubleTapListener,但是所有的方法体都是空的),该类是static class,也就是说它实际上是一个外部类。程序员可以在外部继承这个类,重写里面的手势处理方法
public
static
class
SimpleOnGestureListener
implements
OnGestureListener
,
OnDoubleTapListener
,
OnContextClickListener
{
//单击抬起
public
boolean
onSingleTapUp
(
MotionEvent
e
)
{
return
false
;
}
//长按
public
void
onLongPress
(
MotionEvent
e
)
{
}
//滚动
public
boolean
onScroll
(
MotionEvent
e1
,
MotionEvent
e2
,
float
distanceX
,
float
distanceY
)
{
return
false
;
}
//快速滑动
public
boolean
onFling
(
MotionEvent
e1
,
MotionEvent
e2
,
float
velocityX
,
float
velocityY
)
{
return
false
;
}
//
public
void
onShowPress
(
MotionEvent
e
)
{
}
public
boolean
onDown
(
MotionEvent
e
)
{
return
false
;
}
public
boolean
onDoubleTap
(
MotionEvent
e
)
{
return
false
;
}
public
boolean
onDoubleTapEvent
(
MotionEvent
e
)
{
return
false
;
}
public
boolean
onSingleTapConfirmed
(
MotionEvent
e
)
{
return
false
;
}
public
boolean
onContextClick
(
MotionEvent
e
)
{
return
false
;
}
}
下面是我们自定继承SimpleOnGestureListener,由于我们只要响应单击和双击事件,那么我们只需要重写onDoubleTap双击(),onSingleTapConfirmed(单击)方法即可,
public
class
MyGestureDetector
extends
GestureDetector
.
SimpleOnGestureListener
{
@Override
public
boolean
onDoubleTap
(
MotionEvent
e
)
{
getHandler
().
removeCallbacks
(
singleTapThread
);
singleTapThread
=
null
;
Snackbar
.
make
(
CustomBall
.
this
,
"暂停进度,是否重置进度?"
,
Snackbar
.
LENGTH_LONG
).
setAction
(
"重置"
,
new
OnClickListener
()
{
@Override
public
void
onClick
(
View
v
)
{
currentProgress
=
0
;
invalidate
();
}
}).
show
();
return
super
.
onDoubleTap
(
e
);
}
@Override
public
boolean
onSingleTapConfirmed
(
MotionEvent
e
)
{
Snackbar
.
make
(
CustomBall
.
this
,
"单机了"
,
Snackbar
.
LENGTH_LONG
).
setAction
(
"Action"
,
null
).
show
();
startProgressAnimation
();
return
super
.
onSingleTapConfirmed
(
e
);
}
}
当点击时Snackbar做个提醒单击了View,然后调用startProgressAnimation()方法初始化一个线程,通过postDelayed将线程加入的消息队列,延迟100ms执行,通过singleTapThread == null判断条件,避免过多的创建对象
private
void
startProgressAnimation
()
{
if
(
singleTapThread
==
null
)
{
singleTapThread
=
new
SingleTapThread
();
getHandler
().
postDelayed
(
singleTapThread
,
100
);
}
}
我们将SingleTapThread 实现Runnable接口,在run方法里书写我们的处理逻辑,其实很简单,先判断当前进度值是不是大于最大进度(100),如果小于最大的值,我们就将currentProgress(当前进度值)加1的操作,然后调用invalidate()方法重绘界面,之后还需要再次将线程加入消息队列,依然延迟100ms执行。对于当如果当前进度已经加载到100%,此时我们将此线程从消息队列移除。
private
class
SingleTapThread
implements
Runnable
{
@Override
public
void
run
()
{
if
(
currentProgress
maxProgress
)
{
currentProgress
++
;
invalidate
();
getHandler
().
postDelayed
(
singleTapThread
,
100
);
}
else
{
getHandler
().
removeCallbacks
(
singleTapThread
);
}
}
}
接下来还需要注册事件,我们可以在onDraw()方法中通过GestureDetector的构造方法可以将自定义的MyGestureDetector对象传递进去,然后通setOnTouchListener设置监听器,这样GestureDetector能处理不同的手势了
if
(
detector
==
null
){
detector
=
new
GestureDetector
(
new
MyGestureDetector
());
setOnTouchListener
(
new
OnTouchListener
()
{
@Override
public
boolean
onTouch
(
View
v
,
MotionEvent
event
)
{
return
detector
.
onTouchEvent
(
event
);
}
});
}
还有最重要的一点是,View默认是不可点击的,所以我们需要 setClickable(true)设置View可点击的,OK,到这里我们就完成的中心进度值得更新,接下来就开始绘制里面的波浪形状,效果图如下
实现水波浪效果
水波纹效果是通过二阶贝塞尔曲线实现的,先简单看下什么是贝塞尔曲线
在数学的数值分析领域中,贝塞尔曲线(英语:Bézier curve)是电脑图形学中相当重要的参数曲线。更高维度的广泛化贝塞尔曲线就称作贝塞尔曲面,其中贝塞尔三角是一种特殊的实例。
贝塞尔曲线于1962年,由法国工程师皮埃尔·贝塞尔(Pierre Bézier)所广泛发表,他运用贝塞尔曲线来为汽车的主体进行设计。贝塞尔曲线最初由Paul de Casteljau于1959年运用de Casteljau算法开发,以稳定数值的方法求出贝塞尔曲线 – – – – -维基百科
给定点P0、P1,线性贝塞尔曲线只是一条两点之间的直线。这条线由下式给出:
绘制效果为
二次方贝塞尔曲线的路径由给定点P0、P1、P2的函数B(t)追踪: