想要知道关于更多自定义View的实例,请参考:android自定义View索引
先上个效果图,以免大家跑错地了。
没错,就是上面这个。
下面开始实现:
看到了这个效果我们要想到一般是怎么构成的,我一开始看到的思路是间隔一个固定的角度画弧形,然后画完一周,再进行刷新,后来一实现了会发现边缘粗,中间细,明显不符合我们的要求,经过几次试验,我发现画直线是可以胜任这个工作了,那只要画一些直线围绕一个圆形就行了,那下面看看怎么做。
首先要知道画线的函数是什么:
canvas.drawLine(x1, y1, x2, y2, paint);
只需要两个坐标和一个画笔,(x1, y1)是直线起点的位置,(x2, y2)是终点的位置,这样画出来就成了一条直线,不过怎么旋转呢?看这个函数:
canvas.rotate(degree);
这行代码的意思是旋转画板,原来是这样,我们不是去旋转直线,而是去旋转画板,这样就达到了旋转直线的效果。
有人会疑惑了,我画了一条直线,然后旋转画板,再画第二条直线,那第一条直线不也就被旋转了,为什么可以这样呢?
这里我们需要强行解释一波,我把界面比作一张纸,cavas比作一把尺,paint相当于我们的一支笔,那么当我们用尺子在纸上画了一条直线的时候,再去旋转这个尺子的角度,去画第二条线,你说会影响这第一条线的样子嘛?这里也就是这么个道理,虽然有点不讲理,但是毕竟人家这规定的,我们记着就行了,我解释一波是为了方便你们理解。好了,到这是不是就觉得可以了?
No!
还差一点,那就是这个旋转,到底是怎么个旋转?这个旋转一定要有个中心点去围绕着进行旋转,那又要认识一个函数:
canvas.translate(x, y);
这个函数的意思就是移动这个画板的旋转中心,和明显,我们只需要将中心点移动到控件的宽和高的中线交割处即可。
以上三个函数基本上能画出我们的加载动画的样子了,生下来就是怎么产生旋转的感觉了。
我们观察上面的图,会发现每一个线的颜色都不一样,所以,知道了吧。
我们要去控制每一个直线的颜色,很简单的,画直线循环的时候不断更改直线的画笔颜色即可,这样就更像了。
那下面就是刷新问题,这个函数我们必须要认识:
invalidate();
这个函数 的意思就是刷新界面的意思,意思就是会重新调用一次 ondraw 这个方法,然后 ondraw 里面再调用这个方法,就会实现循环了,那么每次循环我们做一些手脚,就会有不同的感觉了。那旋转的感觉就还是用 canvas.rotate(degree) 这个函数 ,每次重新绘制的时候,只要比上次多一个线的角度就可以了,具体的操作细节,大家就参考下面的代码吧:
public class GradientRotationextends View {
private int center;
private PaintlinePaint;
private Handlerhandler;
private int rotation =1;//用来计算旋转是否有一周的标记
private boolean isAnimate =true;//设置动画是否可以旋转
/*
* 下面的数值我们可以根据自己的需要进行调节
*/
private PaintcirclePaint;//用来设置中间小球的颜色等属性,不同项目中都要更改
private int deepenedDegree =8;//颜色渐变的程度,从1到255,推荐6-15
private int numberOfLines =12;//旋转线条的个数,推荐12-15
private int lineCoarseness =5;//线条的粗度,推荐4-6
private int time =20;//动画旋转的速度,数值越大,速度越慢
public GradientRotation(Context context) {
super(context);
initData();
}
public GradientRotation(Context context, AttributeSet attrs) {
super(context, attrs);
initData();
}
private void initData() {
linePaint =new Paint();
circlePaint =new Paint();
handler =new Handler() {
@Override
public void handleMessage(Message msg) {
super.handleMessage(msg);
switch (msg.what) {
case 1:
invalidate();//重绘界面
break;
}
}
};
}
@Override
protected void onMeasure(int widthMeasureSpec,int heightMeasureSpec) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
center = getMeasuredWidth() /2;
}
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
linePaint.setStrokeWidth(lineCoarseness);//设置线条的粗度
circlePaint.setColor(Color.argb(255,255,255,255));//设置中心圆的颜色,我们用的时候需要根据我们的背景进行设置
canvas.translate(center,center);
canvas.rotate((360 /numberOfLines) *rotation);//每次重绘前都要比上一次多(360 / numberOfLines)度,这样才能有旋转的感觉
for (int i =0; i
linePaint.setColor(Color.argb(255,255 -deepenedDegree * i,255 -deepenedDegree * i,255 -deepenedDegree * i));//一共会绘制12个线,每个线的颜色逐渐加深
canvas.drawLine(0,0,center -10,0,linePaint);
canvas.rotate(360 /numberOfLines);
}
canvas.drawCircle(0,0,20,circlePaint);
if (rotation ==numberOfLines) {
rotation =1;
}
rotation++;
//这里用了定时是为了避免界面刷新过快,不好看
if (isAnimate) {
handler.postDelayed(new Runnable() {
@Override
public void run() {
Message message =new Message();
message.what =1;
handler.sendMessage(message);
}
},time);
}
}
//停止动画
public void stopAnimate() {
isAnimate =false;
}
//停止动画
public void startAnimate() {
if (!isAnimate) {//添加这个判断是为了避免重复点击开始动画导致产生多个动画的情况
isAnimate =true;
invalidate();
}
}
}
在布局里面使用的时候直接当普通控件给个宽高即可。需要注意的是,我这个不止绘制了直线,中心还有一个圆,必须要和我们的北京一个颜色,才能使用,具体的画读者可以自己去更改。
喜欢我的文章的,请点击关注我哦。万学冬的简书