最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

Android仿微信清理內(nèi)存圖表動(dòng)畫(解決surfaceView屏幕閃爍問題)demo實(shí)例詳解

 更新時(shí)間:2016年09月04日 10:44:34   作者:ZccShadow  
本文通過實(shí)例代碼給大家講解android仿微信清理內(nèi)存圖表動(dòng)畫(解決surfaceView屏幕閃爍問題)的相關(guān)資料,本文介紹的非常詳細(xì),具有參考借鑒價(jià)值,需要的朋友可以參考下

最近接了一個(gè)項(xiàng)目其中有功能要實(shí)現(xiàn)一個(gè)清理內(nèi)存,要求和微信的效果一樣。于是想到用surfaceView而不是繼承view。下面小編給大家解析下實(shí)現(xiàn)思路。

surfaceView是為了解決頻繁繪制動(dòng)畫產(chǎn)生了閃爍,而采用了雙緩沖機(jī)制,即A、B兩個(gè)緩沖輪流顯示在畫布上,同時(shí),使用不當(dāng),同樣容易產(chǎn)生閃爍,這是由于A、B中有一個(gè)緩沖沒有改變。

在我寫這個(gè)view的時(shí)候就遇到了這個(gè)問題,研究了好久終于解決。

首先說(shuō)一下思路:

微信清理緩存的動(dòng)畫是:

一個(gè)圓環(huán)不停的轉(zhuǎn)動(dòng),同時(shí)中間有文字顯示-->加載完成后,出現(xiàn)一個(gè)慢慢展開的圖標(biāo),同時(shí)第一塊區(qū)域要突出一點(diǎn)。

這就是微信的動(dòng)畫效果。但是具體實(shí)現(xiàn)是怎么樣的呢?

下面說(shuō)一下我實(shí)現(xiàn)的方法:

1、旋轉(zhuǎn)圓環(huán):

這個(gè)圓環(huán)由兩部分組成,一個(gè)圓和一個(gè)深灰的弧線,而弧線一直在轉(zhuǎn)動(dòng),產(chǎn)生了圓環(huán)在旋轉(zhuǎn)的效果。

因此,這個(gè)就很好解決了。我們畫兩個(gè)圖形,一個(gè)圓形,一個(gè)弧線,而弧線的角度不停的變化就產(chǎn)了旋轉(zhuǎn)的效果。為了讓它不斷變化,就要用到一個(gè)動(dòng)畫類ValueAnimator,通過這個(gè)類不停的給出一個(gè)角度,然后我們不停的繪制,就可以完成這個(gè)效果。

2、文字:

文字是和圓環(huán)是一部分的,當(dāng)然他們其實(shí)應(yīng)該同時(shí)繪制。但是每次繪制,為了避免文字的重疊,我們需要將canvas清除。

我們通過計(jì)算出總的旋轉(zhuǎn)動(dòng)畫時(shí)間和一個(gè)由繪制動(dòng)畫開始,到具體當(dāng)前繪制時(shí)的時(shí)間差來(lái)模擬出百分比。

3、會(huì)展開的圖表:

這個(gè)是這個(gè)效果的難點(diǎn)部分,這里遇到的問題也比較多。

這是一個(gè)慢慢展開的動(dòng)畫,看似是一個(gè)圓在慢慢顯現(xiàn),其實(shí)不是。只不過是一個(gè)扇形再不停的旋轉(zhuǎn),但是沒有清除之前的畫布,這樣產(chǎn)生了平鋪效果。而第一塊區(qū)域的扇形較大只不過是半徑大一點(diǎn)而已。因此這部分我們同樣利用ValueAnimator,也可以畫出。

通過對(duì)第一個(gè)旋轉(zhuǎn)動(dòng)畫進(jìn)行監(jiān)聽,當(dāng)?shù)谝粋€(gè)效果結(jié)束的時(shí)候,第二個(gè)圖表的動(dòng)畫開始進(jìn)行。

4、具體的內(nèi)存大小信息:

這個(gè)比較簡(jiǎn)單,只需要確定坐標(biāo)即可,但是在寫的時(shí)候也遇到了閃爍情況。

下面是具體實(shí)現(xiàn)

最初版本:

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; 
//中間內(nèi)存信息方塊的坐標(biāo) 
private float centerDetailLeft; 
private float centerDetailTop; 
private float centerDetailRight; 
private float centerDetailBottom; 
//chart外接正方形坐標(biāo) 
private float chartLeft; 
private float chartTop; 
private float chartRight; 
private float chartBottom; 
//起始角度 
private float startAngle = 270; 
//半徑 
private float radius; 
//各區(qū)域角度 
private float area1Angle; 
private float area2Angle; 
//區(qū)域的量 
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; 
} 
}

效果:

模仿微信的效果基本顯示出來(lái)了,但是當(dāng)區(qū)域改變的時(shí)候,會(huì)不停閃爍,其實(shí)下面標(biāo)注信息的小正方形也在閃爍,只不過我已經(jīng)修改好了。

查了網(wǎng)上許多方法都沒有給出一個(gè)很直接的答案,大部分都是說(shuō)要對(duì)surfaceView前后緩存都進(jìn)行繪制,這樣就不產(chǎn)生閃爍問題。還有一種方法就是通過背景覆蓋,讓A緩沖在該區(qū)域的背景與B緩沖相同,這樣自然而然切換的時(shí)候,就不會(huì)看到緩存交替而產(chǎn)生的閃爍問題了。

關(guān)于第一種,我并不是很理解,說(shuō)是每次要改變前后兩個(gè)緩沖,不能只變一個(gè)。。。。。。(網(wǎng)上都是這么說(shuō),但是我到底怎么改才算改?。??)

第二種方法,我經(jīng)過了多次嘗試實(shí)現(xiàn)了,通過切換畫筆之后,每次畫圖都覆蓋上一層,這樣保持了之前閃爍部分的緩存一致。

該部分為找到的一些資料:

雙緩存(Double-buffer)與黑屏閃爍

每個(gè)SurfaceView 對(duì)象有兩個(gè)獨(dú)立的graphic buffer,官方SDK將它們稱作"front buffer"和"back buffer"。

常規(guī)的"double-buffer"會(huì)這么做:每一幀的數(shù)據(jù)都被繪制到back buffer,然后back buffer的內(nèi)容被持續(xù)翻轉(zhuǎn)(flip)到front buffer;屏幕一直顯示front buffer。但Android SurfaceView的"double-buffer"卻是這么做的:在buffer A里繪制內(nèi)容,然后讓屏幕顯示buffer A; 下一個(gè)循環(huán),在buffer B里繪制內(nèi)容,然后讓屏幕顯示buffer B; 如此往復(fù)。于是,屏幕上顯示的內(nèi)容依次來(lái)自buffer A, B, A, B,....這樣看來(lái),兩個(gè)buffer其實(shí)沒有主從的分別,與其稱之為"front buffer""back buffer",毋寧稱之為"buffer A""buffer B"。

Android中"double-buffer"的實(shí)現(xiàn)機(jī)制,可以很好地解釋閃屏現(xiàn)象。在第一個(gè)"lockCanvas-drawCanvas-unlockCanvasAndPost"循環(huán)中,更新的是buffer A的內(nèi)容;到下一個(gè)"lockCanvas-drawCanvas-unlockCanvasAndPost"循環(huán)中,更新的是buffer B的內(nèi)容。如果buffer A與buffer B中某個(gè)buffer內(nèi)容為空,當(dāng)屏幕輪流顯示它們時(shí),就會(huì)出現(xiàn)畫面黑屏閃爍現(xiàn)象。

解決方法

出現(xiàn)黑屏是因?yàn)閎uffer A與buffer B中一者內(nèi)容為空,而且為空的一方還被post到了屏幕。于是有兩種解決思路:

不讓空buffer出現(xiàn):每次向一個(gè)buffer寫完內(nèi)容并post之后,順便用這個(gè)buffer的內(nèi)容填充另一個(gè)buffer。這樣能保證兩個(gè)buffer的內(nèi)容是同步的,缺點(diǎn)是做了無(wú)用功,耗費(fèi)性能。

不post空buffer到屏幕:當(dāng)準(zhǔn)備更新內(nèi)容時(shí),先判斷內(nèi)容是否為空,只有非空時(shí)才啟動(dòng)"lockCanvas-drawCanvas-unlockCanvasAndPost"這個(gè)流程。

就好比,A緩存是白色,B緩沖是黑色(也就是前后surfaceView的緩存)。而黑色是surfaceView的默認(rèn)色。比如下面的偽代碼,通過線程不停的繪制:

canvas = holder.lockCanvas(); 
if(flag) { 
canvas.drawColor(Color.WHITE); 
} 
holder.unlockCanvasAndPost(canvas); 
flag = false;

看似沒有什么問題,但是在實(shí)際過程卻一直在黑白閃爍,這就是因?yàn)?,雖然A我們每次都繪制了,但是B一直沒變還是黑色。這時(shí),我們通過覆蓋,講背景變?yōu)榘咨徒鉀Q了這個(gè)問題,而我的解決方法也類似于這種。

下面貼出代碼:

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; 
//中間內(nèi)存信息方塊的坐標(biāo) 
private float centerDetailLeft; 
private float centerDetailTop; 
private float centerDetailRight; 
private float centerDetailBottom; 
//chart外接正方形坐標(biāo) 
private float chartLeft; 
private float chartTop; 
private float chartRight; 
private float chartBottom; 
//起始角度 
private float startAngle = 270; 
//半徑 
private float radius; 
//各區(qū)域角度 
private float area1Angle; 
private float area2Angle; 
//區(qū)域的量 
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; 
} 
}

效果:

同時(shí)建議每個(gè)圖形都用自己的paint,而不是通過重新set不同設(shè)置來(lái)調(diào)用paint,因?yàn)樵谑褂脮r(shí),我發(fā)現(xiàn),因?yàn)楹芏嗟胤接玫氖峭粋€(gè)paint也導(dǎo)致了閃爍,而為每個(gè)圖形都創(chuàng)建了自己的paint之后就好了。

以上所述是小編給大家介紹的Android仿微信清理內(nèi)存圖表動(dòng)畫(解決surfaceView屏幕閃爍問題)demo實(shí)例詳解,希望對(duì)大家有所幫助,如果大家有任何疑問請(qǐng)給我留言,小編會(huì)及時(shí)回復(fù)大家的。在此也非常感謝大家對(duì)腳本之家網(wǎng)站的支持!

相關(guān)文章

  • Android繪制音樂播放器示波器

    Android繪制音樂播放器示波器

    這篇文章主要為大家詳細(xì)介紹了Android繪制音樂播放器示波器的相關(guān)資料,感興趣的小伙伴們可以參考一下
    2016-07-07
  • Android淺析viewBinding和DataBinding

    Android淺析viewBinding和DataBinding

    這篇文章主要介紹了Android淺析viewBinding和DataBinding,文章圍繞主題展開詳細(xì)的內(nèi)容介紹,具有一定的參考價(jià)值,需要的小伙伴可以參考一下
    2022-09-09
  • 解決android viewmodel 數(shù)據(jù)刷新異常的問題

    解決android viewmodel 數(shù)據(jù)刷新異常的問題

    這篇文章主要介紹了解決android viewmodel 數(shù)據(jù)刷新異常的問題,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過來(lái)看看吧
    2020-03-03
  • Android 啟動(dòng)模式詳細(xì)介紹

    Android 啟動(dòng)模式詳細(xì)介紹

    這篇文章主要介紹了Android 啟動(dòng)模式詳細(xì)介紹的相關(guān)資料,Activity一共有以下四種launchMode啟動(dòng)模式,這里一一做詳解,需要的朋友可以參考下
    2016-12-12
  • 解決Android 沉浸式狀態(tài)欄和華為虛擬按鍵沖突問題

    解決Android 沉浸式狀態(tài)欄和華為虛擬按鍵沖突問題

    對(duì)于現(xiàn)在的 App 來(lái)說(shuō),布局頁(yè)面基本都會(huì)用到沉浸式狀態(tài)欄,單純的沉浸式狀態(tài)欄很容易解決,但是在華為手機(jī)上存在一個(gè)底部虛擬按鍵的問題,會(huì)導(dǎo)致頁(yè)面底部和頂部出現(xiàn)很大的問題,下面通過本文給大家分享Android 沉浸式狀態(tài)欄和華為虛擬按鍵沖突問題,一起看看吧
    2017-07-07
  • Android自定義控件實(shí)現(xiàn)優(yōu)雅的廣告輪播圖

    Android自定義控件實(shí)現(xiàn)優(yōu)雅的廣告輪播圖

    這篇文章主要為大家詳細(xì)介紹了Android自定義控件實(shí)現(xiàn)優(yōu)雅的廣告輪播圖,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2017-03-03
  • Android使用百度地圖出現(xiàn)閃退及定位時(shí)顯示藍(lán)屏問題的解決方法

    Android使用百度地圖出現(xiàn)閃退及定位時(shí)顯示藍(lán)屏問題的解決方法

    這篇文章主要介紹了Android使用百度地圖出現(xiàn)閃退及定位時(shí)顯示藍(lán)屏問題的解決方法,需要的朋友可以參考下
    2018-01-01
  • Android自定義ProgressDialog加載圖片

    Android自定義ProgressDialog加載圖片

    這篇文章主要介紹了Android自定義ProgressDialog系統(tǒng)加載框,通過本文大家可以嘗試?yán)肁ndroid自定義ProgressDialog,感興趣的小伙伴們可以參考一下
    2016-05-05
  • Android入門之TableLayout應(yīng)用解析(一)

    Android入門之TableLayout應(yīng)用解析(一)

    這篇文章主要介紹了Android入門之TableLayout應(yīng)用,需要的朋友可以參考下
    2014-08-08
  • AndroidStudio4.1 自定義模板的使用方法

    AndroidStudio4.1 自定義模板的使用方法

    這篇文章主要介紹了AndroidStudio4.1 自定義模板的使用方法,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧
    2021-01-01

最新評(píng)論

昌乐县| 桃园市| 保德县| 修武县| 桑植县| 武城县| 鄢陵县| 蒲江县| 齐齐哈尔市| 鹤庆县| 东兰县| 泸州市| 石家庄市| 凤山市| 马关县| 民和| 临澧县| 黎城县| 夏津县| 中牟县| 关岭| 乌拉特前旗| 永昌县| 齐齐哈尔市| 武宣县| 安乡县| 滨海县| 德州市| 迁安市| 镇江市| 楚雄市| 马龙县| 稻城县| 平顶山市| 肇庆市| 河南省| 迁安市| 赣州市| 永宁县| 工布江达县| 蒲江县|