Android 사용자 정의 View 메모리 청소 가속 볼 효과 구현

17511 단어 AndroidView가속 구
머리말
치타 청소 마스터 나 비슷 한 보안 소프트웨어 를 사용 한 적 이 있 습 니 다.모두 가 알 고 있 는 기능 이 있 습 니 다.그것 은 바로 메모리 청소 입 니 다.보 여 주 는 형식 은 둥 근 작은 공 을 통 해 메모리 크기 를 표시 하고 백분율 숫자 와 진도 바 의 형식 으로 정리 의 진 도 를 표시 하 는 것 입 니 다.본 고 는 이 효과 의 실현 과정 에 대해 상세 하 게 설명 할 것 이지 만 메모리 청소 의 실현 은 언급 되 지 않 을 것 이다.
미리 보기
최종 실현 효과 가 어떤 지 먼저 살 펴 보 겠 습 니 다.

위의 그림 에서 우 리 는 볼 수 있다.
① 가속 구 뷰 가 표 시 될 때 진도 게이지 와 백분율 숫자 는 0%에서 특정한 수치(60%)로 증가한다.
② 진도 게이지 가 멈 추 면 가운데 원 이 Y 축 을 따라 뒤 집 히 기 시작 하고 180 도 뒤 집 히 며 위의 백분율 숫자 에 미 러 효과 가 나타 나 지 않 습 니 다(아래 언급).
③ 사용자 가 이 작은 공 을 클릭 한 후에 메모 리 를 정리 하기 시작 하면 진도 바 와 백분율 숫자 는 0 으로 줄 어 들 고 0 에서 특정한 수치 로 증가 하 는 과정 을 거 친다.
실현 과정 상세 설명
사실 위의 효 과 는 필 자 는 치타 가 대사의 가속 구 를 정리 하 는 것 을 본 떠 서 이 루어 진 것 으로 약간 다 르 지만 대체적으로 형식 이 같다.독자 가 위의 효과 에 관심 이 있다 면 계속 읽 어 보 세 요.다음은 본문 부분 입 니 다.
1 단계 초기 화
우 리 는 먼저 LieBaoView 를 새로 만들어 야 합 니 다.자바,자체 View 를 계승 하여 다음 과 같은 구조 함 수 를 다시 씁 니 다.

public LieBaoView(Context context) {
  super(context);
  init();
 }

 public LieBaoView(Context context, AttributeSet attrs) {
  super(context, attrs);
  init();
 }

 public LieBaoView(Context context, AttributeSet attrs, int defStyleAttr) {
  super(context, attrs, defStyleAttr);
  init();
 }

어떤 방식 으로 이 View 를 예화 하 든 init()방법 을 호출 합 니 다.이 방법 은 주로 각종 구성원 변 수 를 초기 화 하 는 데 사 용 됩 니 다.그러면 우 리 는 어떤 구성원 변수 나 어떤 인 스 턴 스 가 필요 합 니까?
필자 의 생각 은 다음 과 같다.빈 비트 맵 을 통 해 우 리 는 위 에 원형,문자 등 을 그립 니 다.그러면 마지막 으로 이 비트 맵 을 우리 의 view 위 에 그립 니 다.
따라서 초기 화 할 때 각종 Paint(화필),Bitmap(빈 그림),Canvas(캔버스)등의 인 스 턴 스 를 가 져 와 야 합 니 다.다시 한 번 생각해 보 겠 습 니 다.중간의 원 은 회전 할 수 있 습 니 다.그러면 중간의 회전 원 은 다른 원 과 같은 bitmap 에 놓 을 수 없습니다.그렇지 않 으 면 뒤에서 회전 하 는 실현 에 번 거 로 움 을 줄 수 있 기 때문에 우 리 는 두 장의 빈 bitmap 를 준비 할 수 있 습 니 다.그러면 우 리 는 먼저 이렇게 할 수 있다.

public void init(){
  //        
  mBackgroundCirclePaint = new Paint();
  mBackgroundCirclePaint.setAntiAlias(true);
  mBackgroundCirclePaint.setColor(Color.argb(0xff, 0x10, 0x53, 0xff));

  //        
  mFrontCirclePaint = new Paint();
  mFrontCirclePaint.setAntiAlias(true);
  mFrontCirclePaint.setColor(Color.argb(0xff, 0x5e, 0xae, 0xff));

  //       
  mTextPaint = new Paint();
  mTextPaint.setAntiAlias(true);
  mTextPaint.setTextSize(80);
  mTextPaint.setColor(Color.WHITE);

  //        
  mArcPaint = new Paint();
  mArcPaint.setAntiAlias(true);
  mArcPaint.setColor(Color.WHITE);
  mArcPaint.setStrokeWidth(12);
  mArcPaint.setStyle(Paint.Style.STROKE);

  mBitmap = Bitmap.createBitmap(mWidth,mHeight, Bitmap.Config.ARGB_8888);
  mBitmapCanvas = new Canvas(mBitmap); //    Bitmap  

  //  bitmap   
  mOverturnBitmap = Bitmap.createBitmap(mWidth,mHeight, Bitmap.Config.ARGB_8888);
  mOverturnBitmapCanvas = new Canvas(mOverturnBitmap);

  //      ...
  //Camera、Matrix、Runnable      
  mMatrix = new Matrix();
  mCamera = new Camera();
}

위 에 서 는 다양한 화필 유형 을 초기 화하 고 비트 맵 과 그 와 관련 된 캔버스 두 개 를 준 비 했 는데,우 리 는 그 와 관련 된 캔버스 에 그리 면 된다.그러면 내용 이 있 는 비트 맵 두 개 를 얻 을 수 있다.
우 리 는 이 어 뒤 집기 효 과 를 실현 하려 면 무엇이 더 필요 할 까?라 고 생각 했다.Android SDK 는 카메라 와 Matrix 라 는 도 구 를 준비 해 주 었 습 니 다.이 두 도 구 를 이용 하면 크기 조정,이동,반전 등 Bitmap 에 대한 다양한 변환 을 편리 하 게 실현 할 수 있 습 니 다.Camera 와 Matrix 에 관 해 서 는 독자 들 이 더 자세 한 관련 지식 을 검색 할 수 있 으 므 로 자세 한 이 야 기 는 전개 되 지 않 습 니 다.마지막 으로 우 리 는 Runnable 이 필요 합 니 다.자동 반전 과 진도 바 의 자동 증가 와 감 소 를 실현 해 야 하기 때문에 Runnable 은 다음 에 상세 하 게 설명 할 것 입 니 다.서 두 르 지 마 세 요.물론 클릭 모니터 도 설치 해 야 합 니 다.
단계 2.그림 그리 기
위 에는 이미 우 리 를 위해 붓,캔버스 등 이 준비 되 어 있 으 며,우 리 는 다음 에 필요 한 그림 을 그 릴 것 이다.View 의 onDraw()방법 을 다시 쓰 면 됩 니 다.
① 배경 원,즉 위의 그림 에서 가장 바깥쪽 짙 은 파란색 원 을 그립 니 다.
mBitmapCanvas.drawCircle(mWidth / 2, mHeight / 2, mWidth / 2, mBackgroundCirclePaint);
② 가운데 에 있 는 흰색 배경 원 을 그립 니 다.즉,회전 원 을 뒤 집 는 과정 에서 배경의 흰색 부분 을 그립 니 다.
mBitmapCanvas.drawCircle(mWidth / 2, mHeight / 2, mWidth / 2 - mPadding, mTextPaint);
③ 진도 바 를 그립 니 다.원호 형 진도 바 는 어떻게 실현 해 야 합 니까?여기 서 필자 의 생각 을 제시 합 니 다.canvas 의 draw Arc()방법 을 통 해 이 방법 은 사각형 에서 가장 큰 원(또는 타원)을 그 릴 수 있 습 니 다.붓 을 중 공 으로 설정 하고 붓 라인 의 폭 을 12 정도 로 설정 하면 굵 은 포물선 을 실현 할 수 있 습 니 다.그리고 onDraw()방법 을 계속 호출 할 수 있 습 니 다.draw Arc()의 각 도 를 수정 하여 진도 조 효 과 를 실현 합 니 다.만약 여러분 에 게 또 다른 실현 방법 이 있다 면,교 류 를 환영 합 니 다.

 mBitmapCanvas.save();
//       ,               Bitmap    ,      
//               
RectF rectF = new RectF(10,10,mWidth-10,mHeight-10);
//         90 ,  drawArc        0   ,        
mBitmapCanvas.rotate(-90, mWidth / 2, mHeight / 2);
mBitmapCanvas.drawArc(rectF, 0, ((float)mProgress/mMaxProgress)*360, false, mArcPaint);
mBitmapCanvas.restore();
canvas.drawBitmap(mBitmap, 0, 0, null);
④ 가운데 회전 원 을 그립 니 다.위 에서 말 했 듯 이 반전 효 과 를 실현 하려 면 같은 비트 맵 에 그 릴 수 없 기 때문에 우 리 는 다른 빈 비트 맵 을 사용 합 니 다.회전 원 의 그리 기 는 매우 간단 합 니 다.그것 의 반지름 이 바깥 원 의 반지름 과 진도 조 의 너비 보다 더 작 으 면 됩 니 다.
mOverturnBitmapCanvas.drawCircle(mWidth / 2, mHeight / 2, mWidth / 2 - mPadding, mFrontCirclePaint);
⑤ 마지막 으로 회전 원 에 백분율 숫자 를 그립 니 다.텍스트 를 그립 니 다.Canvas 의 drawText 방법 을 사용 해 야 합 니 다.이 방법 을 중점적으로 살 펴 보 겠 습 니 다.

 /**
  * Draw the text, with origin at (x,y), using the specified paint. The
  * origin is interpreted based on the Align setting in the paint.
  *
  * @param text The text to be drawn
  * @param x  The x-coordinate of the origin of the text being drawn
  * @param y  The y-coordinate of the baseline of the text being drawn
  * @param paint The paint used for the text (e.g. color, size, style)
  */
 public void drawText(@NonNull String text, float x, float y, @NonNull Paint paint) {
  //...
 }
첫 번 째 와 네 번 째 매개 변 수 는 할 말 이 없다.두 번 째 매개 변 수 는 문자 가 시 작 된 x 좌 표를 나타 내 고 세 번 째 매개 변 수 는 문자 의 baseline 의 y 좌 표를 나타 낸다.텍스트 를 가운데 로 표시 하려 면 적당 한 x,y 좌표 만 설정 하면 됩 니 다.그러면 baseline 은 무엇 입 니까?그것 은 사실 텍스트 의 기준점 을 대표 하고 있 습 니 다.우 리 는 그림 을 보 겠 습 니 다.

그림 에서 알 수 있 듯 이 baseline 이상 에서 텍스트 의 최고점 은 Ascent 이 고 마이너스 이다.baseline 아래 에서 텍스트 의 가장 낮은 점 은 Descent 이 고 플러스 입 니 다.따라서 만약 에 우리 가 텍스트 를 컨트롤 안에 가운데 로 표시 하려 면-(ascent-descent)/2 를 이용 하여 텍스트 의 높이 의 절반 을 계산 할 수 있 습 니 다.이때 mHeight/2(컨트롤 높이 의 절반)를 이용 하여 이 값 을 더 하면 컨트롤 에 있 는 baseline 값 을 얻 을 수 있 습 니 다.이때 중간 에 표 시 됩 니 다.코드 는 다음 과 같 습 니 다.

String text = (int) (((float)mProgress / mMaxProgress) *100) + "%";
//       
 float textWidth = mTextPaint.measureText(text);
//      
Paint.FontMetrics metrics = mTextPaint.getFontMetrics();
float baseLine = mHeight / 2 - (metrics.ascent + metrics.descent) /2;
mOverturnBitmapCanvas.drawText(text, mWidth / 2 - textWidth / 2, baseLine, mTextPaint);
마지막 으로 bitmap 를 view 에 그립 니 다.
canvas.drawBitmap(mOverturnBitmap, mMatrix, null);
이상 의 그림 을 통 해 우 리 는 먼저 효과 가 어떤 지 봅 시다.

그럼 기본 적 인 효 과 는 다 이 루어 졌 습 니 다.다음 에 우 리 는 동적 효 과 를 실현 할 것 이다.
Step 3.자동 반전 효과 구현
위의 애니메이션 효 과 를 보면 우 리 는 먼저 진도 바 를 0 에서 특정한 수치 로 증가 시 킨 다음 에 자동 으로 뒤 집 습 니 다.수 치 를 증가 시 키 는 것 은 간단 합 니 다.Runnable 을 사용 하면 Runnable 에서 mProgress 값 을 계속 증가 시 키 고 invalidate()방법 으로 View 를 새로 고침 하면 됩 니 다.진도 가 증가 하면 뒤 집기 시작 합 니 다.뒤 집기 시작 하면 Camera 와 Matrix 를 이용 하여 중간의 bitmap 를 조작 하고 각 도 를 계속 바 꾸 면 이 루어 집 니 다.코드 를 살 펴 보 겠 습 니 다.
onDraw()방법 에서:

 @Override
 protected void onDraw(Canvas canvas) {
  //....

  //        
  if(isRotating) {
   mCamera.save();
   //    
   mCamera.rotateY(mRotateAngle);
   //           180    ,  180 
   if (mRotateAngle >= 180) {
    mRotateAngle -= 180;
   }
   //  Camera           
   mCamera.getMatrix(mMatrix);
   mCamera.restore();
   mMatrix.preTranslate(-mWidth / 2, -mHeight / 2);
   mMatrix.postTranslate(mWidth / 2, mHeight / 2);
  }

  canvas.drawBitmap(mOverturnBitmap, mMatrix, null);

  //              
  if(!isRotating && !isInital){
   //  isIncreasing,             
   isIncreasing = true;
   isRotating = true;
   postDelayed(mRotateRunnable,10);
}

이어서 mRotateRunnable 을 쓰 겠 습 니 다.Runnable 의 초기 화 는 init()방법 에 있 습 니 다.

mRotateRunnable = new Runnable() {
 @Override
 public void run() {

  //           
  if(isIncreasing){
   Log.d("cylog","mProgress:"+mProgress);
   //              ,    
   if(mProgress >= 59){
    isIncreasing = false;
   }
   mProgress++;
  }else {
   //        ,      
   //  mRotateAngle   90  ,  bitmap     90 ,
   //  bitmap         ,         ,       180 ,
   //           ,     180  onDraw    。
   if (mRotateAngle > 90 && mRotateAngle < 180)
    mRotateAngle = mRotateAngle + 3 + 180;
   //  mRotateAngle   180 ,      
   else if (mRotateAngle >= 180) {
    isRotating = false;
    isInital = true;
    mRotateAngle = 0;
    return;
   } else
    //      3,      ,    
    mRotateAngle += 3;
  }
  invalidate();
  //25ms        
  postDelayed(this,25);
 }
};

이상 의 Runnable 및 onDraw()방법의 배합 을 통 해 자동 반전 효 과 를 실현 할 수 있 습 니 다.
Step 4.클릭 하여 청소 하 는 효과 구현
자,마지막 효 과 를 실현 하 겠 습 니 다.마찬가지 로 저 희 는 Runnable 을 이용 하여 이 루어 집 니 다.이 청소 효 과 는 사용자 가 작은 공 을 클릭 한 후에 청 소 를 시작 해 야 하기 때문에 이벤트 모니터 가 필요 합 니 다.사용자 가 클릭 할 때마다 onClick 방법 에 Runnable 을 게시 하면 됩 니 다.
먼저 mCleaning Runnable 을 실현 하고 init()방법 에서:

mCleaningRunnable = new Runnable() {
 @Override
 public void run() {
  //            ,      
  if (mProgress >= 60) {
   isCleaning = false;
   return;
  }
  //          ,mProgress    ,   0
  if (isDescending) {
   mProgress--;
   if (mProgress <= 0)
    isDescending = false;
  } else {
   mProgress++;
  }
  invalidate();
  postDelayed(this,40);
 }
};

setOnClickListener(new OnClickListener() {
  @Override
  public void onClick(View v) {
  if(isCleaning) return;
   //          ,    return,  post  
   //  flag,     
   isDescending = true;
   isCleaning = true;
   mProgress--;
   postDelayed(mCleaningRunnable, 40);
  }
});

위의 논 리 는 실 현 됩 니 다.클릭 할 때마다 진도 치 를 0 까지 줄 이 고 그 다음 에 특정한 값 까지 계속 증가 합 니 다.모든 호출 invalidate()방법 을 통 해 구성 요소 의 갱신 을 알 리 면 동적 효 과 를 실현 합 니 다.
자,지금까지 모든 효과 가 이 루어 졌 습 니 다.모든 코드 를 아래 에 붙 입 니 다.읽 어 주 셔 서 감사합니다.

public class LieBaoView extends View {

 private Paint mBackgroundCirclePaint;
 private Paint mFrontCirclePaint;
 private Paint mTextPaint;
 private Paint mArcPaint;
 private Bitmap mBitmap;
 private Bitmap mOverturnBitmap;
 private Canvas mBitmapCanvas;
 private Canvas mOverturnBitmapCanvas;
 private Matrix mMatrix;
 private Camera mCamera;
 private int mWidth = 400;
 private int mHeight = 400;
 private int mPadding = 20;
 private int mProgress = 0;
 private int mMaxProgress = 100;
 private int mRotateAngle = 0;
 private Runnable mRotateRunnable;
 private Runnable mCleaningRunnable;
 private boolean isRotating;
 private boolean isInital = false;
 private boolean isDescending;
 private boolean isIncreasing;
 private boolean isCleaning;
 public LieBaoView(Context context) {
  super(context);
  init();
 }

 public LieBaoView(Context context, AttributeSet attrs) {
  super(context, attrs);
  init();
 }

 public LieBaoView(Context context, AttributeSet attrs, int defStyleAttr) {
  super(context, attrs, defStyleAttr);
  init();
 }

 @Override
 protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
  setMeasuredDimension(mWidth,mHeight);
 }

 public void init(){
  //        
  mBackgroundCirclePaint = new Paint();
  mBackgroundCirclePaint.setAntiAlias(true);
  mBackgroundCirclePaint.setColor(Color.argb(0xff, 0x10, 0x53, 0xff));

  //        
  mFrontCirclePaint = new Paint();
  mFrontCirclePaint.setAntiAlias(true);
  mFrontCirclePaint.setColor(Color.argb(0xff, 0x5e, 0xae, 0xff));

  //       
  mTextPaint = new Paint();
  mTextPaint.setAntiAlias(true);
  mTextPaint.setTextSize(80);
  mTextPaint.setColor(Color.WHITE);

  //        
  mArcPaint = new Paint();
  mArcPaint.setAntiAlias(true);
  mArcPaint.setColor(Color.WHITE);
  mArcPaint.setStrokeWidth(12);
  mArcPaint.setStyle(Paint.Style.STROKE);

  mBitmap = Bitmap.createBitmap(mWidth,mHeight, Bitmap.Config.ARGB_8888);
  mBitmapCanvas = new Canvas(mBitmap); //    Bitmap  

  //  bitmap   
  mOverturnBitmap = Bitmap.createBitmap(mWidth,mHeight, Bitmap.Config.ARGB_8888);
  mOverturnBitmapCanvas = new Canvas(mOverturnBitmap);

  mMatrix = new Matrix();
  mCamera = new Camera();

  mRotateRunnable = new Runnable() {
   @Override
   public void run() {

    //           
    if(isIncreasing){
     Log.d("cylog","mProgress:"+mProgress);
     //              ,    
     if(mProgress >= 59){
      isIncreasing = false;
     }
     mProgress++;
    }else {
     //        ,      
     //  mRotateAngle   90  ,  bitmap     90 ,
     //  bitmap         ,         ,       180 ,
     //           ,     180  onDraw    。
     if (mRotateAngle > 90 && mRotateAngle < 180)
      mRotateAngle = mRotateAngle + 3 + 180;
     //  mRotateAngle   180 ,      
     else if (mRotateAngle >= 180) {
      isRotating = false;
      isInital = true;
      mRotateAngle = 0;
      return;
     } else
      //      3,      ,    
      mRotateAngle += 3;
    }
    invalidate();
    //25ms        
    postDelayed(this,25);
   }
  };

  mCleaningRunnable = new Runnable() {
   @Override
   public void run() {
    //            ,      
    if (mProgress >= 60) {
     isCleaning = false;
     return;
    }
    //          ,mProgress    ,   0
    if (isDescending) {
     mProgress--;
     if (mProgress <= 0)
      isDescending = false;
    } else {
     mProgress++;
    }
    invalidate();
    postDelayed(this,40);
   }
  };

  setOnClickListener(new OnClickListener() {
   @Override
   public void onClick(View v) {
    if(isCleaning) return;

    isDescending = true;
    isCleaning = true;
    mProgress--;
    postDelayed(mCleaningRunnable, 40);
   }
  });
 }

 @Override
 protected void onDraw(Canvas canvas) {
  mBitmapCanvas.drawCircle(mWidth / 2, mHeight / 2, mWidth / 2, mBackgroundCirclePaint);
  mBitmapCanvas.drawCircle(mWidth / 2, mHeight / 2, mWidth / 2 - mPadding, mTextPaint);

   mBitmapCanvas.save();
  //       ,               Bitmap    ,      
  //               
  RectF rectF = new RectF(10,10,mWidth-10,mHeight-10);
  //         90 ,  drawArc        0   ,        
  mBitmapCanvas.rotate(-90, mWidth / 2, mHeight / 2);
  mBitmapCanvas.drawArc(rectF, 0, ((float)mProgress/mMaxProgress)*360, false, mArcPaint);
  mBitmapCanvas.restore();
  canvas.drawBitmap(mBitmap, 0, 0, null);

  mOverturnBitmapCanvas.drawCircle(mWidth / 2, mHeight / 2, mWidth / 2 - mPadding, mFrontCirclePaint);
  String text = (int) (((float)mProgress / mMaxProgress) *100) + "%";
  //       
  float textWidth = mTextPaint.measureText(text);
  //      
  Paint.FontMetrics metrics = mTextPaint.getFontMetrics();
  float baseLine = mHeight / 2 - (metrics.ascent + metrics.descent) /2;
  mOverturnBitmapCanvas.drawText(text, mWidth / 2 - textWidth / 2, baseLine, mTextPaint);

  //        
  if(isRotating) {
   mCamera.save();
   //    
   mCamera.rotateY(mRotateAngle);
   //           180    ,  180 
   if (mRotateAngle >= 180) {
    mRotateAngle -= 180;
   }
   //  Camera           
   mCamera.getMatrix(mMatrix);
   mCamera.restore();
   mMatrix.preTranslate(-mWidth / 2, -mHeight / 2);
   mMatrix.postTranslate(mWidth / 2, mHeight / 2);
  }

  canvas.drawBitmap(mOverturnBitmap, mMatrix, null);

  //              
  if(!isRotating && !isInital){
   //  isIncreasing,             
   isIncreasing = true;
   isRotating = true;
   postDelayed(mRotateRunnable,10);
  }
 }
}

이상 이 바로 본 고의 모든 내용 입 니 다.여러분 의 학습 에 도움 이 되 고 저 희 를 많이 응원 해 주 셨 으 면 좋 겠 습 니 다.

좋은 웹페이지 즐겨찾기