前言:我是真的很菜.....
公司项目做加载图的时候第一时间就叫UI给了一张GIF图,glide很完美的加载出来了,本来是没什么事的,但是被吐槽gif锯齿太明显了。后来换了张精致一点的,但是体积大了近十倍,结果就OOM了。查了查资料,没有找到glide中有更好的解决办法。也试过使用开源的gif-drawable但还是蹦了,最后没办法自己画吧。
用到的主要类及方法:
Paint:
setColor 设置颜色
setStrokeWidth 设置画笔宽度
setAntiAlias 消除锯齿(看中的就是这个)
setAlpha 设置画笔透明度
setXfermode 设置叠加模式(这个还是挺重要的)
path
moveTo 起始轮廓点移至x,y坐标点
lineTo 从当前轮廓点绘制一条线段到
close 回到初始点形成闭环
quadTo 绘制一个贝塞尔曲线
成品图
就是一个透明度随着中间水流不断上涨的加载图。这图大概分为三层
1:底层灰色的圆 直接绘制就好
2:中间的流水(这张图的流水其实是个假的,根本就没动,只需要让他的高度不断上涨就行了,同时变化透明度与第三层的图标)
3:绘制一个图标
代码
public classWaterDrawableextendsDrawable{
private static finalStringTAG="WaterDrawable";
/***
* 四个画笔 四条线
*/
privatePaintmPaint;
privatePaintbluePaint;
privatePaintpencilTopPaint;
privatePaintpencilBottomPaint;
privatePathmWaterPath;
privatePathcriclePath;
privatePathpencilTopPath;
privatePathpencilBottomPath;
//圆的高度
private intmCricleHeight=180;
//透明度初始值
private intAlpha=125;
//高度变量值
private intmMultNum=0;
//水的高宽
private intmWaterHeight=180;
private intmWaterWidth=180;
//循环的handler与是否首次绘制
privateHandlermLoophandler;
privateBooleanisFirst=true;
/***
* 初始化画笔以及路径
*/
publicWaterDrawable() {
mPaint=newPaint();
mPaint.setColor(MakeLearnApplication.getAppContext().getResources().getColor(R.color.gray_qian));
mPaint.setStyle(Paint.Style.FILL);
mPaint.setAntiAlias(true);
bluePaint=newPaint();
bluePaint.setColor(MakeLearnApplication.getAppContext().getResources().getColor(R.color.main_back_qian));
bluePaint.setStyle(Paint.Style.FILL);
bluePaint.setAntiAlias(true);
//设置这个叠加模式 使底部的view变成最大的边
PorterDuffXfermode xfermode =newPorterDuffXfermode(PorterDuff.Mode.SRC_ATOP);
bluePaint.setXfermode(xfermode);
bluePaint.setStrokeWidth(5);
pencilTopPaint=newPaint();
pencilTopPaint.setColor(Color.WHITE);
pencilTopPaint.setStyle(Paint.Style.FILL);
PorterDuffXfermode pencilTopXfermode =newPorterDuffXfermode(PorterDuff.Mode.ADD);
pencilTopPaint.setXfermode(pencilTopXfermode);
pencilTopPaint.setAntiAlias(true);
pencilBottomPaint=newPaint();
pencilBottomPaint.setColor(Color.WHITE);
pencilBottomPaint.setStyle(Paint.Style.FILL);
PorterDuffXfermode pencilBottomXfermode =newPorterDuffXfermode(PorterDuff.Mode.ADD);
pencilBottomPaint.setXfermode(pencilBottomXfermode);
pencilBottomPaint.setAntiAlias(true);
criclePath=newPath();
pencilTopPath=newPath();
pencilBottomPath=newPath();
mLoophandler=newHandler();
}
/***
* 绘制
*@paramcanvas
*/
@Override
public voiddraw(@NonNullCanvas canvas) {
Log.i(TAG,"drawSSSS: "+Alpha);
mPaint.setAlpha(Alpha);
pencilBottomPaint.setAlpha(Alpha);
pencilTopPaint.setAlpha(Alpha);
//画个圆
criclePath.addCircle(mCricleHeight/2,mCricleHeight/2,
mCricleHeight/2,Path.Direction.CCW);
criclePath.close();
canvas.drawPath(criclePath,mPaint);
//画个水
mWaterHeight=mCricleHeight-mMultNum;
mWaterPath=newPath();
mWaterPath.moveTo(0,mWaterHeight/2);
mWaterPath.quadTo(mWaterWidth/4,mWaterHeight/3,
mWaterWidth/2,mWaterHeight/2);
mWaterPath.quadTo(mWaterWidth*3/4,mWaterHeight/3*2,
mWaterWidth,mWaterHeight/2);
mWaterPath.lineTo(mWaterWidth,mWaterWidth);
mWaterPath.lineTo(0,mWaterWidth);
mWaterPath.close();
canvas.drawPath(mWaterPath,bluePaint);
//画个铅笔头
pencilTopPath.moveTo(mCricleHeight/2,mCricleHeight/9*2);
pencilTopPath.lineTo(mCricleHeight/6*4,mCricleHeight/16*7);
pencilTopPath.quadTo(mCricleHeight/12*7,mCricleHeight/32*13,
mCricleHeight/2,mCricleHeight/16*7);
pencilTopPath.quadTo(mCricleHeight/12*5,mCricleHeight/32*13,
mCricleHeight/6*2,mCricleHeight/16*7);
pencilTopPath.close();
canvas.drawPath(pencilTopPath,pencilTopPaint);
//画个铅笔干
pencilBottomPath.moveTo(mCricleHeight/6*2,mCricleHeight/16*8);
pencilBottomPath.quadTo(mCricleHeight/12*5,mCricleHeight/32*15,
mCricleHeight/2,mCricleHeight/2);
pencilBottomPath.quadTo(mCricleHeight/12*7,mCricleHeight/32*15,
mCricleHeight/6*4,mCricleHeight/2);
pencilBottomPath.lineTo(mCricleHeight/3*2,mCricleHeight/4*3);
pencilBottomPath.quadTo(mCricleHeight/12*7,mCricleHeight/32*23,
mCricleHeight/2,mCricleHeight/16*12);
pencilBottomPath.quadTo(mCricleHeight/12*5,mCricleHeight/32*23,
mCricleHeight/6*2,mCricleHeight/16*12);
pencilBottomPath.close();
canvas.drawPath(pencilBottomPath,pencilBottomPaint);
//循环绘制
if(isFirst){
mLoophandler.postDelayed(mRunnable,100);
isFirst=false;
}
}
@Override
public voidsetAlpha(inti) {
mPaint.setAlpha(i);
}
@Override
public voidsetColorFilter(ColorFilter colorFilter) {
mPaint.setColorFilter(colorFilter);
}
@Override
public intgetOpacity() {
returnPixelFormat.TRANSPARENT;
}
RunnablemRunnable=newRunnable() {
@Override
public voidrun() {
if(mMultNum<=mCricleHeight){
mMultNum+=20;
Alpha= (int) (125+100*((float)mMultNum/mCricleHeight));
}else{
mMultNum=0;
Alpha=125;
}
invalidateSelf();//重新绘制
mLoophandler.postDelayed(mRunnable,70);
}
};
}
解析
1:第二层的水流如何实现只在最底层的圆中?
使用画笔的叠加模式setXfermode
PorterDuffXfermode xfermode =newPorterDuffXfermode(PorterDuff.Mode.SRC_ATOP);
bluePaint.setXfermode(xfermode);
2:如何绘制出中间的铅笔呢?
使用path的quadTo方法 绘制曲线,贝塞尔曲线非常灵活,可以满足很大一部分的要求
3:如何实现刷新的。
drawable类的invalidateSelf方法可以重新绘制图像,配合handler即可。
问题:
当我不断的刷新这个图像的时候,就会变得卡顿,本来是70毫秒一次,最后卡成了一秒一次,请懂得大神,小神指导一下。