欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  移动技术

Android仿微信清理内存图表动画(解决surfaceView屏幕闪烁问题)demo实例详解

程序员文章站 2024-03-06 12:15:44
最近接了一个项目其中有功能要实现一个清理内存,要求和微信的效果一样。于是想到用surfaceview而不是继承view。下面小编给大家解析下实现思路。 surfacevi...

最近接了一个项目其中有功能要实现一个清理内存,要求和微信的效果一样。于是想到用surfaceview而不是继承view。下面小编给大家解析下实现思路。

surfaceview是为了解决频繁绘制动画产生了闪烁,而采用了双缓冲机制,即a、b两个缓冲轮流显示在画布上,同时,使用不当,同样容易产生闪烁,这是由于a、b中有一个缓冲没有改变。

在我写这个view的时候就遇到了这个问题,研究了好久终于解决。

首先说一下思路:

微信清理缓存的动画是:

一个圆环不停的转动,同时中间有文字显示-->加载完成后,出现一个慢慢展开的图标,同时第一块区域要突出一点。

这就是微信的动画效果。但是具体实现是怎么样的呢?

下面说一下我实现的方法:

1、旋转圆环:

这个圆环由两部分组成,一个圆和一个深灰的弧线,而弧线一直在转动,产生了圆环在旋转的效果。

因此,这个就很好解决了。我们画两个图形,一个圆形,一个弧线,而弧线的角度不停的变化就产了旋转的效果。为了让它不断变化,就要用到一个动画类valueanimator,通过这个类不停的给出一个角度,然后我们不停的绘制,就可以完成这个效果。

2、文字:

文字是和圆环是一部分的,当然他们其实应该同时绘制。但是每次绘制,为了避免文字的重叠,我们需要将canvas清除。

我们通过计算出总的旋转动画时间和一个由绘制动画开始,到具体当前绘制时的时间差来模拟出百分比。

3、会展开的图表:

这个是这个效果的难点部分,这里遇到的问题也比较多。

这是一个慢慢展开的动画,看似是一个圆在慢慢显现,其实不是。只不过是一个扇形再不停的旋转,但是没有清除之前的画布,这样产生了平铺效果。而第一块区域的扇形较大只不过是半径大一点而已。因此这部分我们同样利用valueanimator,也可以画出。

通过对第一个旋转动画进行监听,当第一个效果结束的时候,第二个图表的动画开始进行。

4、具体的内存大小信息:

这个比较简单,只需要确定坐标即可,但是在写的时候也遇到了闪烁情况。

下面是具体实现

最初版本:

package xiaoqi.expandablechartview; 
import android.animation.animator; 
import android.animation.propertyvaluesholder; 
import android.animation.valueanimator; 
import android.content.context; 
import android.graphics.canvas; 
import android.graphics.color; 
import android.graphics.paint; 
import android.graphics.pixelformat; 
import android.graphics.porterduff; 
import android.graphics.rectf; 
import android.util.attributeset; 
import android.view.surfaceholder; 
import android.view.surfaceview; 
import android.view.animation.linearinterpolator; 
public class chartview extends surfaceview implements surfaceholder.callback { 
private context context; 
private surfaceholder holder; 
private valueanimator chartanimator; 
private valueanimator circleanimator; 
//中间内存信息方块的坐标 
private float centerdetailleft; 
private float centerdetailtop; 
private float centerdetailright; 
private float centerdetailbottom; 
//chart外接正方形坐标 
private float chartleft; 
private float charttop; 
private float chartright; 
private float chartbottom; 
//起始角度 
private float startangle = 270; 
//半径 
private float radius; 
//各区域角度 
private float area1angle; 
private float area2angle; 
//区域的量 
private float total; 
private float area1; 
private float area2; 
private long time; 
private int repeatcount = 2; 
//是否为第一次显示,用于防止surface闪烁 
private boolean area1isfirstshow = true; 
private boolean area2isfirstshow = true; 
//大扇形外接正方形 
private rectf rectf; 
//小扇形外接正方形 
private rectf rectf2; 
private paint area1paint; 
private paint area2paint; 
private paint area3paint; 
private paint circlepaint; 
private paint arcpaint; 
private paint loadingpaint; 
private paint textpaint; 
private static final int circle_duration = 1000; 
public chartview(context context) { 
super(context); 
this.context = context; 
init(); 
} 
public chartview(context context, attributeset attrs) { 
super(context, attrs); 
this.context = context; 
init(); 
} 
public chartview(context context, attributeset attrs, int defstyleattr) { 
super(context, attrs, defstyleattr); 
this.context = context; 
init(); 
} 
private void init() { 
radius = utility.dip2px(context, 100); 
holder = getholder(); 
holder.addcallback(this); 
setzorderontop(true); 
holder.setformat(pixelformat.translucent); 
initpaint(); 
initanimator(); 
} 
private void initanimator() { 
propertyvaluesholder anglevalues = propertyvaluesholder.offloat("angle", 0f, 360f); 
chartanimator = valueanimator.ofpropertyvaluesholder(anglevalues); 
chartanimator.setduration(2000); 
chartanimator.setinterpolator(new linearinterpolator()); 
chartanimator.addupdatelistener(new valueanimator.animatorupdatelistener() { 
@override 
public void onanimationupdate(valueanimator animation) { 
float angle = obj2float(animation.getanimatedvalue("angle")); 
canvas canvas = holder.lockcanvas(null); 
if(canvas != null){ 
// canvas.drawcolor(color.transparent, porterduff.mode.clear); 
drawdetail(canvas); 
// canvas.setdrawfilter(new paintflagsdrawfilter(0, paint.anti_alias_flag | paint.filter_bitmap_flag)); 
// if (!area1isfirstshow) { 
// canvas.drawarc(rectf, startangle, area1angle, true, area1paint); 
// } 
// if (!area2isfirstshow) { 
// canvas.drawarc(rectf2, area1angle + startangle, area2angle, true, area2paint); 
// } 
if (angle < area1angle) { 
canvas.drawarc(rectf, startangle, angle, true, area1paint); 
} else if (angle <= area2angle + area1angle) { 
// if (area1isfirstshow) { 
// area1isfirstshow = false; 
// canvas.drawarc(rectf, startangle, area1angle, true, area1paint); 
// } else { 
canvas.drawarc(rectf2, startangle+area1angle, angle - area1angle, true, area2paint); 
// } 
} else { 
// if (area2isfirstshow) { 
// area2isfirstshow = false; 
// canvas.drawarc(rectf2, area1angle + startangle, area2angle, true, area2paint); 
// } else { 
canvas.drawarc(rectf2, startangle + area1angle + area2angle, angle - area2angle - area1angle, 
true, area3paint); 
// } 
} 
holder.unlockcanvasandpost(canvas); 
} 
} 
}); 
circleanimator = valueanimator.ofpropertyvaluesholder(anglevalues); 
circleanimator.setinterpolator(new linearinterpolator()); 
circleanimator.setduration(circle_duration); 
circleanimator.addupdatelistener(new valueanimator.animatorupdatelistener() { 
@override 
public void onanimationupdate(valueanimator animation) { 
float angle = obj2float(animation.getanimatedvalue("angle")); 
canvas canvas = holder.lockcanvas(null); 
if(canvas != null){ 
long nowtime = system.currenttimemillis(); 
int rate = (int) (nowtime - time) / (circle_duration * (repeatcount + 1) / 100); 
if (rate <= 100) { 
canvas.drawcolor(color.transparent, porterduff.mode.clear); 
canvas.drawtext("正在加载" + rate + "%", getmeasuredwidth() / 2 - radius / 2, 
getmeasuredheight() / 2, loadingpaint); 
} 
canvas.drawcircle(getmeasuredwidth() / 2, getmeasuredheight() / 2 - utility.dip2px(context, 10), 
radius, circlepaint); 
canvas.drawarc(rectf2, 180 + angle, 30, false, arcpaint); 
holder.unlockcanvasandpost(canvas); 
} 
} 
}); 
circleanimator.addlistener(new animator.animatorlistener() { 
@override 
public void onanimationstart(animator animation) { 
time = system.currenttimemillis(); 
} 
@override 
public void onanimationend(animator animation) { 
chartanimator.start(); 
} 
@override 
public void onanimationcancel(animator animation) { 
} 
@override 
public void onanimationrepeat(animator animation) { 
} 
}); 
} 
private void initpaint() { 
area1paint = new paint(); 
area1paint.setantialias(true); 
area1paint.setstyle(paint.style.fill); 
area1paint.settextsize((utility.dip2px(context, 15))); 
area1paint.setcolor(context.getresources().getcolor(r.color.background_blue)); 
area2paint = new paint(); 
area2paint.setantialias(true); 
area2paint.setstyle(paint.style.fill); 
area2paint.settextsize((utility.dip2px(context, 15))); 
area2paint.setcolor(context.getresources().getcolor(r.color.chart_blue)); 
area3paint = new paint(); 
area3paint.setantialias(true); 
area3paint.setstyle(paint.style.fill); 
area3paint.settextsize((utility.dip2px(context, 15))); 
area3paint.setcolor(context.getresources().getcolor(r.color.light_gary)); 
circlepaint = new paint(); 
circlepaint.setantialias(true); 
circlepaint.setstrokewidth(utility.dip2px(context, 5)); 
circlepaint.setstyle(paint.style.stroke); 
circlepaint.setcolor(context.getresources().getcolor(r.color.background_gray)); 
arcpaint = new paint(); 
arcpaint.setantialias(true); 
arcpaint.setstrokewidth(utility.dip2px(context, 5)); 
arcpaint.setstyle(paint.style.stroke); 
arcpaint.setcolor(context.getresources().getcolor(r.color.textcolor_gray)); 
loadingpaint = new paint(); 
loadingpaint.settextsize((utility.dip2px(context, 15))); 
loadingpaint.setcolor(context.getresources().getcolor(r.color.textcolor_gray)); 
textpaint = new paint(); 
textpaint.settextsize((utility.dip2px(context, 15))); 
textpaint.setcolor(context.getresources().getcolor(r.color.black)); 
} 
private float obj2float(object o) { 
return ((number) o).floatvalue(); 
} 
@override 
protected void onmeasure(int widthmeasurespec, int heightmeasurespec) { 
super.onmeasure(widthmeasurespec, heightmeasurespec); 
chartleft = getmeasuredwidth() / 2 - radius; 
charttop = getmeasuredheight() / 2 - radius - utility.dip2px(context, 10); 
chartright = getmeasuredwidth() / 2 + radius; 
chartbottom = getmeasuredheight() / 2 + radius - utility.dip2px(context, 10); 
centerdetailleft = getmeasuredwidth() / 2 - utility.dip2px(context, 20); 
centerdetailtop = getmeasuredheight() / 2 + radius + utility.dip2px(context, 15); 
centerdetailright = getmeasuredwidth() / 2; 
centerdetailbottom = getmeasuredheight() / 2 + radius + utility.dip2px(context, 35); 
} 
@override 
protected void ondraw(canvas canvas) { 
super.ondraw(canvas); 
} 
@override 
public void surfacecreated(surfaceholder holder) { 
rectf = new rectf(chartleft - utility.dip2px(context, 5), charttop - utility.dip2px(context, 5), chartright + 
utility.dip2px(context, 5), chartbottom + utility.dip2px(context, 5)); 
rectf2 = new rectf(chartleft, charttop, chartright, chartbottom); 
// valueanimator.start(); 
} 
@override 
public void surfacechanged(surfaceholder holder, int format, int width, int height) { 
} 
@override 
public void surfacedestroyed(surfaceholder holder) { 
circleanimator.cancel(); 
chartanimator.cancel(); 
} 
private void drawdetail(canvas canvas) { 
canvas.drawrect(centerdetailleft - utility.dip2px(context, 150), centerdetailtop, 
centerdetailright - utility.dip2px(context, 150), centerdetailbottom, area1paint); 
canvas.drawrect(centerdetailleft, centerdetailtop, centerdetailright, centerdetailbottom, area2paint); 
canvas.drawrect(centerdetailleft + utility.dip2px(context, 150), centerdetailtop, 
centerdetailright + utility.dip2px(context, 150), centerdetailbottom, area3paint); 
drawtext(canvas); 
} 
private void drawtext(canvas canvas) { 
canvas.drawtext("本软件", centerdetailright - utility.dip2px(context, 150) + utility.dip2px(context, 5), 
centerdetailtop + utility.dip2px(context, 10), area1paint); 
canvas.drawtext("200mb", centerdetailright - utility.dip2px(context, 150) + utility.dip2px(context, 5), 
centerdetailtop + utility.dip2px(context, 25), textpaint); 
canvas.drawtext("其他", centerdetailright + utility.dip2px(context, 5), 
centerdetailtop + utility.dip2px(context, 10), area2paint); 
canvas.drawtext("24.1gb", centerdetailright + utility.dip2px(context, 5), 
centerdetailtop + utility.dip2px(context, 25), textpaint); 
canvas.drawtext("可用", centerdetailright + utility.dip2px(context, 150) + utility.dip2px(context, 5), 
centerdetailtop + utility.dip2px(context, 10), area3paint); 
canvas.drawtext("30gb", centerdetailright + utility.dip2px(context, 150) + utility.dip2px(context, 5), 
centerdetailtop + utility.dip2px(context, 25), textpaint); 
} 
public void show() { 
circleanimator.setrepeatcount(repeatcount); 
circleanimator.start(); 
} 
public void setarea1color(int color) { 
area1paint.setcolor(color); 
} 
public void setarea2color(int color) { 
area2paint.setcolor(color); 
} 
public void setarea3color(int color) { 
area3paint.setcolor(color); 
} 
public void setradius(float radius) { 
this.radius = radius; 
} 
public void setscale(float total, float area1, float area2){ 
area1angle = area1/total * 360; 
area2angle = area2/total * 360; 
} 
public void setrepeatcount(int repeatcount){ 
this.repeatcount = repeatcount; 
} 
}

效果:

Android仿微信清理内存图表动画(解决surfaceView屏幕闪烁问题)demo实例详解

模仿微信的效果基本显示出来了,但是当区域改变的时候,会不停闪烁,其实下面标注信息的小正方形也在闪烁,只不过我已经修改好了。

查了网上许多方法都没有给出一个很直接的答案,大部分都是说要对surfaceview前后缓存都进行绘制,这样就不产生闪烁问题。还有一种方法就是通过背景覆盖,让a缓冲在该区域的背景与b缓冲相同,这样自然而然切换的时候,就不会看到缓存交替而产生的闪烁问题了。

关于第一种,我并不是很理解,说是每次要改变前后两个缓冲,不能只变一个。。。。。。(网上都是这么说,但是我到底怎么改才算改!!?)

第二种方法,我经过了多次尝试实现了,通过切换画笔之后,每次画图都覆盖上一层,这样保持了之前闪烁部分的缓存一致。

该部分为找到的一些资料:

双缓存(double-buffer)与黑屏闪烁

每个surfaceview 对象有两个独立的graphic buffer,官方sdk将它们称作"front buffer"和"back buffer"。

常规的"double-buffer"会这么做:每一帧的数据都被绘制到back buffer,然后back buffer的内容被持续翻转(flip)到front buffer;屏幕一直显示front buffer。但android surfaceview的"double-buffer"却是这么做的:在buffer a里绘制内容,然后让屏幕显示buffer a; 下一个循环,在buffer b里绘制内容,然后让屏幕显示buffer b; 如此往复。于是,屏幕上显示的内容依次来自buffer a, b, a, b,....这样看来,两个buffer其实没有主从的分别,与其称之为"front buffer""back buffer",毋宁称之为"buffer a""buffer b"。

android中"double-buffer"的实现机制,可以很好地解释闪屏现象。在第一个"lockcanvas-drawcanvas-unlockcanvasandpost"循环中,更新的是buffer a的内容;到下一个"lockcanvas-drawcanvas-unlockcanvasandpost"循环中,更新的是buffer b的内容。如果buffer a与buffer b中某个buffer内容为空,当屏幕轮流显示它们时,就会出现画面黑屏闪烁现象。

解决方法

出现黑屏是因为buffer a与buffer b中一者内容为空,而且为空的一方还被post到了屏幕。于是有两种解决思路:

不让空buffer出现:每次向一个buffer写完内容并post之后,顺便用这个buffer的内容填充另一个buffer。这样能保证两个buffer的内容是同步的,缺点是做了无用功,耗费性能。

不post空buffer到屏幕:当准备更新内容时,先判断内容是否为空,只有非空时才启动"lockcanvas-drawcanvas-unlockcanvasandpost"这个流程。

就好比,a缓存是白色,b缓冲是黑色(也就是前后surfaceview的缓存)。而黑色是surfaceview的默认色。比如下面的伪代码,通过线程不停的绘制:

canvas = holder.lockcanvas(); 
if(flag) { 
canvas.drawcolor(color.white); 
} 
holder.unlockcanvasandpost(canvas); 
flag = false;

看似没有什么问题,但是在实际过程却一直在黑白闪烁,这就是因为,虽然a我们每次都绘制了,但是b一直没变还是黑色。这时,我们通过覆盖,讲背景变为白色,就解决了这个问题,而我的解决方法也类似于这种。

下面贴出代码:

package xiaoqi.expandablechartview; 
import android.animation.animator; 
import android.animation.propertyvaluesholder; 
import android.animation.valueanimator; 
import android.content.context; 
import android.graphics.canvas; 
import android.graphics.color; 
import android.graphics.paint; 
import android.graphics.pixelformat; 
import android.graphics.porterduff; 
import android.graphics.rectf; 
import android.util.attributeset; 
import android.view.surfaceholder; 
import android.view.surfaceview; 
import android.view.animation.linearinterpolator; 
public class chartview extends surfaceview implements surfaceholder.callback { 
private context context; 
private surfaceholder holder; 
private valueanimator chartanimator; 
private valueanimator circleanimator; 
//中间内存信息方块的坐标 
private float centerdetailleft; 
private float centerdetailtop; 
private float centerdetailright; 
private float centerdetailbottom; 
//chart外接正方形坐标 
private float chartleft; 
private float charttop; 
private float chartright; 
private float chartbottom; 
//起始角度 
private float startangle = 270; 
//半径 
private float radius; 
//各区域角度 
private float area1angle; 
private float area2angle; 
//区域的量 
private float total; 
private float area1; 
private float area2; 
private long time; 
private int repeatcount = 2; 
//是否为第一次显示,用于防止surface闪烁 
private boolean area1isfirstshow = true; 
private boolean area2isfirstshow = true; 
//大扇形外接正方形 
private rectf rectf; 
//小扇形外接正方形 
private rectf rectf2; 
private paint area1paint; 
private paint area2paint; 
private paint area3paint; 
private paint circlepaint; 
private paint arcpaint; 
private paint loadingpaint; 
private paint textpaint; 
private static final int circle_duration = 1000; 
public chartview(context context) { 
super(context); 
this.context = context; 
init(); 
} 
public chartview(context context, attributeset attrs) { 
super(context, attrs); 
this.context = context; 
init(); 
} 
public chartview(context context, attributeset attrs, int defstyleattr) { 
super(context, attrs, defstyleattr); 
this.context = context; 
init(); 
} 
private void init() { 
radius = utility.dip2px(context, 100); 
holder = getholder(); 
holder.addcallback(this); 
setzorderontop(true); 
holder.setformat(pixelformat.translucent); 
initpaint(); 
initanimator(); 
} 
private void initanimator() { 
propertyvaluesholder anglevalues = propertyvaluesholder.offloat("angle", 0f, 360f); 
chartanimator = valueanimator.ofpropertyvaluesholder(anglevalues); 
chartanimator.setduration(2000); 
chartanimator.setinterpolator(new linearinterpolator()); 
chartanimator.addupdatelistener(new valueanimator.animatorupdatelistener() { 
@override 
public void onanimationupdate(valueanimator animation) { 
float angle = obj2float(animation.getanimatedvalue("angle")); 
canvas canvas = holder.lockcanvas(null); 
if(canvas != null){ 
canvas.drawcolor(color.transparent, porterduff.mode.clear); 
drawdetail(canvas); 
// canvas.setdrawfilter(new paintflagsdrawfilter(0, paint.anti_alias_flag | paint.filter_bitmap_flag)); 
if (!area1isfirstshow) { 
canvas.drawarc(rectf, startangle, area1angle, true, area1paint); 
} 
if (!area2isfirstshow) { 
canvas.drawarc(rectf2, area1angle + startangle, area2angle, true, area2paint); 
} 
if (angle < area1angle) { 
canvas.drawarc(rectf, startangle, angle, true, area1paint); 
} else if (angle <= area2angle + area1angle) { 
if (area1isfirstshow) { 
area1isfirstshow = false; 
canvas.drawarc(rectf, startangle, area1angle, true, area1paint); 
} else { 
canvas.drawarc(rectf2, startangle+area1angle, angle - area1angle, true, area2paint); 
} 
} else { 
if (area2isfirstshow) { 
area2isfirstshow = false; 
canvas.drawarc(rectf2, area1angle + startangle, area2angle, true, area2paint); 
} else { 
canvas.drawarc(rectf2, startangle + area1angle + area2angle, angle - area2angle - area1angle, 
true, area3paint); 
} 
} 
holder.unlockcanvasandpost(canvas); 
} 
} 
}); 
circleanimator = valueanimator.ofpropertyvaluesholder(anglevalues); 
circleanimator.setinterpolator(new linearinterpolator()); 
circleanimator.setduration(circle_duration); 
circleanimator.addupdatelistener(new valueanimator.animatorupdatelistener() { 
@override 
public void onanimationupdate(valueanimator animation) { 
float angle = obj2float(animation.getanimatedvalue("angle")); 
canvas canvas = holder.lockcanvas(null); 
if(canvas != null){ 
long nowtime = system.currenttimemillis(); 
int rate = (int) (nowtime - time) / (circle_duration * (repeatcount + 1) / 100); 
if (rate <= 100) { 
canvas.drawcolor(color.transparent, porterduff.mode.clear); 
canvas.drawtext("正在加载" + rate + "%", getmeasuredwidth() / 2 - radius / 2, 
getmeasuredheight() / 2, loadingpaint); 
} 
canvas.drawcircle(getmeasuredwidth() / 2, getmeasuredheight() / 2 - utility.dip2px(context, 10), 
radius, circlepaint); 
canvas.drawarc(rectf2, 180 + angle, 30, false, arcpaint); 
holder.unlockcanvasandpost(canvas); 
} 
} 
}); 
circleanimator.addlistener(new animator.animatorlistener() { 
@override 
public void onanimationstart(animator animation) { 
time = system.currenttimemillis(); 
} 
@override 
public void onanimationend(animator animation) { 
chartanimator.start(); 
} 
@override 
public void onanimationcancel(animator animation) { 
} 
@override 
public void onanimationrepeat(animator animation) { 
} 
}); 
} 
private void initpaint() { 
area1paint = new paint(); 
area1paint.setantialias(true); 
area1paint.setstyle(paint.style.fill); 
area1paint.settextsize((utility.dip2px(context, 15))); 
area1paint.setcolor(context.getresources().getcolor(r.color.background_blue)); 
area2paint = new paint(); 
area2paint.setantialias(true); 
area2paint.setstyle(paint.style.fill); 
area2paint.settextsize((utility.dip2px(context, 15))); 
area2paint.setcolor(context.getresources().getcolor(r.color.chart_blue)); 
area3paint = new paint(); 
area3paint.setantialias(true); 
area3paint.setstyle(paint.style.fill); 
area3paint.settextsize((utility.dip2px(context, 15))); 
area3paint.setcolor(context.getresources().getcolor(r.color.light_gary)); 
circlepaint = new paint(); 
circlepaint.setantialias(true); 
circlepaint.setstrokewidth(utility.dip2px(context, 5)); 
circlepaint.setstyle(paint.style.stroke); 
circlepaint.setcolor(context.getresources().getcolor(r.color.background_gray)); 
arcpaint = new paint(); 
arcpaint.setantialias(true); 
arcpaint.setstrokewidth(utility.dip2px(context, 5)); 
arcpaint.setstyle(paint.style.stroke); 
arcpaint.setcolor(context.getresources().getcolor(r.color.textcolor_gray)); 
loadingpaint = new paint(); 
loadingpaint.settextsize((utility.dip2px(context, 15))); 
loadingpaint.setcolor(context.getresources().getcolor(r.color.textcolor_gray)); 
textpaint = new paint(); 
textpaint.settextsize((utility.dip2px(context, 15))); 
textpaint.setcolor(context.getresources().getcolor(r.color.black)); 
} 
private float obj2float(object o) { 
return ((number) o).floatvalue(); 
} 
@override 
protected void onmeasure(int widthmeasurespec, int heightmeasurespec) { 
super.onmeasure(widthmeasurespec, heightmeasurespec); 
chartleft = getmeasuredwidth() / 2 - radius; 
charttop = getmeasuredheight() / 2 - radius - utility.dip2px(context, 10); 
chartright = getmeasuredwidth() / 2 + radius; 
chartbottom = getmeasuredheight() / 2 + radius - utility.dip2px(context, 10); 
centerdetailleft = getmeasuredwidth() / 2 - utility.dip2px(context, 20); 
centerdetailtop = getmeasuredheight() / 2 + radius + utility.dip2px(context, 15); 
centerdetailright = getmeasuredwidth() / 2; 
centerdetailbottom = getmeasuredheight() / 2 + radius + utility.dip2px(context, 35); 
} 
@override 
protected void ondraw(canvas canvas) { 
super.ondraw(canvas); 
} 
@override 
public void surfacecreated(surfaceholder holder) { 
rectf = new rectf(chartleft - utility.dip2px(context, 5), charttop - utility.dip2px(context, 5), chartright + 
utility.dip2px(context, 5), chartbottom + utility.dip2px(context, 5)); 
rectf2 = new rectf(chartleft, charttop, chartright, chartbottom); 
// valueanimator.start(); 
} 
@override 
public void surfacechanged(surfaceholder holder, int format, int width, int height) { 
} 
@override 
public void surfacedestroyed(surfaceholder holder) { 
circleanimator.cancel(); 
chartanimator.cancel(); 
} 
private void drawdetail(canvas canvas) { 
canvas.drawrect(centerdetailleft - utility.dip2px(context, 150), centerdetailtop, 
centerdetailright - utility.dip2px(context, 150), centerdetailbottom, area1paint); 
canvas.drawrect(centerdetailleft, centerdetailtop, centerdetailright, centerdetailbottom, area2paint); 
canvas.drawrect(centerdetailleft + utility.dip2px(context, 150), centerdetailtop, 
centerdetailright + utility.dip2px(context, 150), centerdetailbottom, area3paint); 
drawtext(canvas); 
} 
private void drawtext(canvas canvas) { 
canvas.drawtext("本软件", centerdetailright - utility.dip2px(context, 150) + utility.dip2px(context, 5), 
centerdetailtop + utility.dip2px(context, 10), area1paint); 
canvas.drawtext("200mb", centerdetailright - utility.dip2px(context, 150) + utility.dip2px(context, 5), 
centerdetailtop + utility.dip2px(context, 25), textpaint); 
canvas.drawtext("其他", centerdetailright + utility.dip2px(context, 5), 
centerdetailtop + utility.dip2px(context, 10), area2paint); 
canvas.drawtext("24.1gb", centerdetailright + utility.dip2px(context, 5), 
centerdetailtop + utility.dip2px(context, 25), textpaint); 
canvas.drawtext("可用", centerdetailright + utility.dip2px(context, 150) + utility.dip2px(context, 5), 
centerdetailtop + utility.dip2px(context, 10), area3paint); 
canvas.drawtext("30gb", centerdetailright + utility.dip2px(context, 150) + utility.dip2px(context, 5), 
centerdetailtop + utility.dip2px(context, 25), textpaint); 
} 
public void show() { 
circleanimator.setrepeatcount(repeatcount); 
circleanimator.start(); 
} 
public void setarea1color(int color) { 
area1paint.setcolor(color); 
} 
public void setarea2color(int color) { 
area2paint.setcolor(color); 
} 
public void setarea3color(int color) { 
area3paint.setcolor(color); 
} 
public void setradius(float radius) { 
this.radius = radius; 
} 
public void setscale(float total, float area1, float area2){ 
area1angle = area1/total * 360; 
area2angle = area2/total * 360; 
} 
public void setrepeatcount(int repeatcount){ 
this.repeatcount = repeatcount; 
} 
}

效果:

Android仿微信清理内存图表动画(解决surfaceView屏幕闪烁问题)demo实例详解

同时建议每个图形都用自己的paint,而不是通过重新set不同设置来调用paint,因为在使用时,我发现,因为很多地方用的是同一个paint也导致了闪烁,而为每个图形都创建了自己的paint之后就好了。

以上所述是小编给大家介绍的android仿微信清理内存图表动画(解决surfaceview屏幕闪烁问题)demo实例详解,希望对大家有所帮助