Android 위 챗 을 모방 하여 메모리 도표 애니메이션 정리(surfaceView 화면 깜빡 임 문제 해결)demo 실례 상세 설명
28483 단어 surfaceview깜박거리다
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;
}
}
효과:위 챗 을 모방 하 는 효 과 는 기본적으로 나 타 났 지만 지역 이 바 뀌 었 을 때 계속 반 짝 거 린 다.사실은 아래 에 표 시 된 정보의 작은 정사각형 도 반 짝 이 고 있 지만 나 는 이미 수정 했다.
인터넷 에서 많은 방법 을 찾 아 보 았 지만 직접적인 답 을 주지 않 았 다.대부분 surfaceView 앞 뒤 캐 시 를 그립 니 다.그러면 반 짝 임 문제 가 발생 하지 않 습 니 다.또 하나의 방법 은 배경 으로 덮어 쓰 고 A 버퍼 가 이 지역 의 배경 이 B 버퍼 와 같 도록 하 는 것 이다.그러면 자 연 스 럽 게 전환 할 때 캐 시 교체 로 인 한 반 짝 임 문 제 를 보지 못 할 것 이다.
첫 번 째 에 대해 저 는 잘 이해 하지 못 합 니 다.매번 앞 뒤 두 개의 버퍼 를 바 꿔 야 한다 고 하 는데 하나만 바 꿀 수 는 없습니다.인터넷 에서 다 그렇게 말 하 는데 내 가 어떻게 고 쳐 야 고 치 는 거 야!!?)
두 번 째 방법 은 제 가 여러 번 시 도 를 통 해 이 루어 졌 습 니 다.붓 을 바 꾼 후에 그림 을 그 릴 때마다 한 층 씩 덮어 서 예전 에 반 짝 였 던 부분의 캐 시 를 일치 시 켰 습 니 다.
이 부분 에서 찾 은 자료 들:
더 블 캐 시(Double-buffer)와 블랙 스크린 이 깜빡 입 니 다.
Surface View 대상 마다 두 개의 독립 된 graphic buffer 가 있 는데 공식 SDK 는 이 를'front buffer'와'back buffer'라 고 부른다.
일반적인"double-buffer"는 이렇게 합 니 다.모든 프레임 의 데 이 터 는 back buffer 에 그 려 진 다음 에 back buffer 의 내용 이 front buffer 로 계속 뒤 집 힙 니 다.화면 에 front buffer 가 계속 표 시 됩 니 다.그러나 Android Surface View 의'double-buffer'는 이렇게 합 니 다.buffer A 에 내용 을 그리고 화면 에 buffer A 를 표시 합 니 다.다음 순환 은 buffer B 에 내용 을 그리고 화면 에 buffer B 를 표시 합 니 다.이렇게 왕복 하 다.그래서 화면 에 표 시 된 내용 은 buffer A,B,A,B,.......................................................................
안 드 로 이 드 의'double-buffer'구현 메커니즘 은 플래시 현상 을 잘 설명 할 수 있다.첫 번 째'lockCanvas-draw Canvas-unlockCanvas AndPost'순환 에서 buffer A 의 내용 을 업데이트 합 니 다.다음'lockCanvas-draw Canvas-unlockCanvasAndPost'순환 에서 buffer B 의 내용 을 업데이트 합 니 다.buffer A 와 buffer B 의 한 buffer 내용 이 비어 있 으 면 화면 이 돌아 가면 서 표 시 될 때 화면 블랙 스크린 반 짝 임 현상 이 나타난다.
해결 방법
블랙 스크린 이 나 온 것 은 버퍼 A 와 버퍼 B 중 하나 가 비어 있 고 비어 있 는 쪽 이 화면 에 게시 되 기 때문이다.그래서 두 가지 해결 방향 이 있다.
빈 버퍼 가 나타 나 지 않도록 합 니 다:매번 한 버퍼 에 내용 을 쓰 고 post 를 한 후에 이 버퍼 의 내용 으로 다른 버퍼 를 채 웁 니 다.이렇게 하면 두 버퍼 의 내용 이 동기 화 되 는 것 을 보장 할 수 있 으 며,단점 은 공 부 를 하지 않 고 성능 을 소모 하 는 것 이다.
화면 에 post 빈 buffer 를 사용 하지 않 음:내용 을 업데이트 하려 고 할 때 내용 이 비어 있 는 지 여 부 를 판단 하고 비어 있 지 않 을 때 만'lockCanvas-draw Canvas-unlockCanvas AndPost'프로 세 스 를 시작 합 니 다.
예 를 들 어 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;
}
}
효과:또한 모든 도형 은 자신의 paint 를 사용 하 는 것 을 권장 합 니 다.다른 설정 을 다시 설정 해서 paint 를 호출 하 는 것 이 아 닙 니 다.사용 할 때 같은 paint 를 사용 하 는 곳 이 많 기 때문에 반 짝 이 고 모든 도형 에 자신의 paint 를 만 들 었 으 면 좋 겠 습 니 다.
위 에서 말 한 것 은 소 편 이 소개 한 안 드 로 이 드 가 위 챗 을 모방 하여 메모리 도표 애니메이션(surfaceView 화면 반 짝 임 문 제 를 해결)demo 인 스 턴 스 를 상세 하 게 설명 하 는 것 입 니 다.여러분 에 게 도움 이 되 기 를 바 랍 니 다.궁금 한 점 이 있 으 시 면 저 에 게 메 시 지 를 남 겨 주세요.소 편 은 제때에 답 해 드 리 겠 습 니 다.여기 서도 저희 사이트 에 대한 여러분 의 지지 에 감 사 드 립 니 다!
이 내용에 흥미가 있습니까?
현재 기사가 여러분의 문제를 해결하지 못하는 경우 AI 엔진은 머신러닝 분석(스마트 모델이 방금 만들어져 부정확한 경우가 있을 수 있음)을 통해 가장 유사한 기사를 추천합니다:
Android 는 Surface View 를 이용 하여 비 오 는 날씨 애니메이션 효 과 를 실현 합 니 다.분석 이 끝나 면 바로 하나의 종 류 를 써 서 View 를 계승 한 다음 에 다시 쓸 수 있 습 니까?효과 그림 의 빗방울 이 떨 어 지 는 속도 가 빠르다 는 것 을 볼 수 있 습 니 다.이 는 프레임 마다onD...
텍스트를 자유롭게 공유하거나 복사할 수 있습니다.하지만 이 문서의 URL은 참조 URL로 남겨 두십시오.
CC BY-SA 2.5, CC BY-SA 3.0 및 CC BY-SA 4.0에 따라 라이센스가 부여됩니다.