老熟女激烈的高潮_日韩一级黄色录像_亚洲1区2区3区视频_精品少妇一区二区三区在线播放_国产欧美日产久久_午夜福利精品导航凹凸

重慶分公司,新征程啟航

為企業(yè)提供網(wǎng)站建設(shè)、域名注冊(cè)、服務(wù)器等服務(wù)

Android自定義Viewapp更新動(dòng)畫詳解

為了做一個(gè)有溫度的IT男,我決定在以后的文章中給大家分享一些看到的,聽到的一些東西,如果你不喜歡請(qǐng)留言讓我知道,如果你喜歡請(qǐng)點(diǎn)個(gè)贊。你也可留言寫下自己想分享的東西,溫暖你我他。這次分享的是一首歌,毛不易的《消愁》,分享這首歌主要是這首歌的歌詞,借用薛之謙的評(píng)價(jià):“我是研究歌詞的人,我研究了十幾年,但是你寫到我想給你跪!”,下面貼部分歌詞供大家欣賞

為應(yīng)縣等地區(qū)用戶提供了全套網(wǎng)頁設(shè)計(jì)制作服務(wù),及應(yīng)縣網(wǎng)站建設(shè)行業(yè)解決方案。主營業(yè)務(wù)為網(wǎng)站制作、做網(wǎng)站、應(yīng)縣網(wǎng)站設(shè)計(jì),以傳統(tǒng)方式定制建設(shè)網(wǎng)站,并提供域名空間備案等一條龍服務(wù),秉承以專業(yè)、用心的態(tài)度為用戶提供真誠的服務(wù)。我們深信只要達(dá)到每一位用戶的要求,就會(huì)得到認(rèn)可,從而選擇與我們長(zhǎng)期合作。這樣,我們也可以走得更遠(yuǎn)!

一杯敬朝陽,一杯敬月光

喚醒我的向往,溫柔了寒窗

于是可以不回頭的逆風(fēng)飛翔

不怕心頭有雨,眼底有霜

一杯敬故鄉(xiāng),一杯敬遠(yuǎn)方

守著我的善良,催著我成長(zhǎng)

所以南北的路從此不再漫長(zhǎng)

靈魂不再無處安放

好了,言歸正傳,本篇文章是實(shí)現(xiàn)項(xiàng)目中的更新功能,效果如下

Android自定義View app更新動(dòng)畫詳解

觀察動(dòng)畫,可以分為幾個(gè)階段:

  • 初始化階段 顯示立即升級(jí)按鈕,在點(diǎn)擊立即升級(jí)按鈕后,執(zhí)行放大再縮小至消失動(dòng)畫
  • 準(zhǔn)備階段 進(jìn)度條背景從中間向兩端擴(kuò)散,然后進(jìn)度提示圖片顯示,進(jìn)度提示文字顯示0%
  • 更新階段 進(jìn)度更新時(shí),進(jìn)度提示圖片和文字旋轉(zhuǎn)向前移動(dòng),如果一定時(shí)間內(nèi)進(jìn)度沒更新的話,進(jìn)度提示圖片和文字要置回水平狀態(tài)
  • 成功階段,進(jìn)度提示圖片縮放消失,進(jìn)度條背景從兩端向中間縮小至消失
  • 安裝階段 馬上安裝圖片放大顯示

1.首選看初始化階段,我們要判斷用戶是否點(diǎn)擊了立即升級(jí)按鈕,我們通過監(jiān)聽onTouchEvent事件判斷手指是否落在可點(diǎn)擊區(qū)域

//如果點(diǎn)擊生效,執(zhí)行動(dòng)畫

if (rectClickRange.contains(event.getX(), event.getY()))
startBtnDisappear();//立即更新按鈕消失動(dòng)畫

其中rectClickRange是我們定義的可點(diǎn)擊區(qū)域,也就是立即更新圖片的顯示區(qū)域

rectClickRange = new RectF(getWidth() / 2 - startDrawable.getWidth() / 2, getHeight() / 2 - startDrawable.getHeight() / 2, getWidth() / 2 + startDrawable.getWidth() / 2, getHeight() / 2 + startDrawable.getHeight() / 2);//startDrawable是立即更新圖片

點(diǎn)擊生效后我們執(zhí)行立即更新按鈕消失動(dòng)畫,代碼如下

/**
 * 點(diǎn)擊立即升級(jí)的時(shí)候,立即升級(jí)按鈕執(zhí)行消失動(dòng)畫
 * 動(dòng)畫效果是按鈕放大一點(diǎn)之后縮小至消失
 * 根據(jù)效果選擇插值器AnticipateInterpolator(開始的時(shí)候向后然后向前甩)
 * 將bitmapscale設(shè)置到立即升級(jí)圖片上
 * 動(dòng)畫結(jié)束后狀態(tài)更新為準(zhǔn)備狀態(tài)
 */

private void startBtnDisappear() {
 initStateData();
 ValueAnimator va = ValueAnimator.ofInt(0, 1);
 va.setInterpolator(new AnticipateInterpolator());
 va.setDuration(800);
 va.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
  @Override
  public void onAnimationUpdate(ValueAnimator animation) {
   bitmapScale = 1 - animation.getAnimatedFraction();
   invalidate();
  }
 });
 va.addListener(new MyAnimationListener() {
  @Override
  public void onAnimationEnd(Animator animation) {
   cancleValueAnimator(va_List);
   state = PREPARE;
   toPrepare();
  }
 });
 va.start();
 va_List.add(va);
}
然后在onDraw里面繪制立即升級(jí)按鈕動(dòng)畫,代碼如下:


    matrix.reset();
    matrix.setScale(bitmapScale, bitmapScale);//縮放圖片
    matrix.preTranslate(0, 0);
    matrix.postTranslate(width / 2 - startDrawable.getWidth() / 2 * bitmapScale, height / 2 - startDrawable.getHeight() / 2 * bitmapScale);//不斷的改變縮放的中心點(diǎn)
    canvas.drawBitmap(startDrawable, matrix, bitmapPaint);

2.接著我們看一下準(zhǔn)備階段,我們通過畫path,并不斷的改變path的起點(diǎn)和終點(diǎn)達(dá)到所需要的動(dòng)畫效果,代碼如下:

/**
 * PREPARE狀態(tài)
 * 進(jìn)度條從中間向兩端擴(kuò)散
 * 具體做法是不斷改變path的起點(diǎn)和終點(diǎn)坐標(biāo)
 * 動(dòng)畫結(jié)束的時(shí)候開始下載更新
 */

private void toPrepare() {
 final ValueAnimator va = ValueAnimator.ofFloat(0, width / 2 - pbPaint.getStrokeWidth() * 3 - pbProgerssDrawable.getWidth());
 va.setInterpolator(new LinearInterpolator());
 va.setDuration(200);
 va.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
  @Override
  public void onAnimationUpdate(ValueAnimator animation) {
   float value = (Float) animation.getAnimatedValue();
   startX = (int) (width / 2 - value);
   endX = (int) (width / 2 + value);
   if (animation.getAnimatedFraction() == 1) prepareDone = true;
   invalidate();
  }
 });
 va.addListener(new MyAnimationListener() {
  @Override
  public void onAnimationEnd(Animator animation) {
   if (startDownLoadListener != null && !isSetListener) {
    isSetListener = true;
    postDelayed(new Runnable() {
     @Override
     public void run() {
      state = UPDATEING;     
      startDownLoadListener.downLoad();//動(dòng)畫結(jié)束,通知界面開始下載apk
      text = progress * 100 / max + "%";
     }
    }, 200);
   }
  }
 });
 va.start();
 va_List.add(va);
}
具體的繪制代碼如下


    pbPath.reset();
    pbPath.moveTo(startX, height / 2);
    pbPath.lineTo(endX, height / 2);
    canvas.drawPath(pbPath, pbPaint);//繪制path
    //進(jìn)度條完全顯示后,畫進(jìn)度提示圖片和文字
    if (prepareDone) {
     canvas.drawBitmap(pbProgerssDrawable, startX - pbProgerssDrawable.getWidth() / 2, height / 2 - pbProgerssDrawable.getHeight() - pbPaint.getStrokeWidth(), bitmapPaint);
     String text = "0%";
     textPaint.getTextBounds(text.toCharArray(), 0, text.toCharArray().length, textRect);
     canvas.drawText(text, startX - textRect.right / 2, height / 2 - pbProgerssDrawable.getHeight() / 2 - pbPaint.getStrokeWidth() + textRect.bottom, textPaint);
    }

3.這個(gè)時(shí)候界面就開始下載apk(代碼不貼了),然后通知view來更新進(jìn)度,更新的動(dòng)畫是圖片和文字旋轉(zhuǎn)向前移動(dòng)(我們的做法是將畫布旋轉(zhuǎn)),如果一定時(shí)間進(jìn)度沒有變化,更新的圖片和文字置回正常狀態(tài)(我們通過啟動(dòng)線程不斷的將畫布旋轉(zhuǎn)回來并更新view,如果這個(gè)階段進(jìn)度有更新的話,我們把線程remove掉),繪制代碼如下

   pbPath.reset();
   pbPath.moveTo(startX, height / 2);
   pbPath.lineTo(endX, height / 2);
   pm.setPath(pbPath, false);
   //不斷截取進(jìn)度到pbPathSec并繪制
   if (progressOffsetX >= pm.getLength()) {
    pm.getSegment(0, pm.getLength(), pbPathSec, true);
    pm.getPosTan(pm.getLength(), POS, null);
   } else {
    pm.getSegment(0, progressOffsetX, pbPathSec, true);
    pm.getPosTan(progressOffsetX, POS, null);
   }
   matrix.reset();
   matrix.setTranslate(POS[0] - pbProgerssDrawable.getWidth() / 2, POS[1] - pbProgerssDrawable.getHeight() - pbPaint.getStrokeWidth());
   canvas.drawPath(pbPath, pbPaint);
   canvas.drawPath(pbPathSec, pbUpdatePaint);
   canvas.save();
   //如果進(jìn)度沒有到達(dá)100%,并且進(jìn)度在更新的時(shí)候,畫布旋轉(zhuǎn),然后畫進(jìn)度提示圖片和文字
   if (progressOffsetX < pm.getLength() && !isRotate) {
    canvas.rotate(-15, POS[0], POS[1] - pbPaint.getStrokeWidth() / 2);
   }
   canvas.drawBitmap(pbProgerssDrawable, matrix, bitmapPaint);
   if (progressOffsetX >= pm.getLength())
    progressOffsetX = pm.getLength();
   text = (int) (progressOffsetX * 100 / pm.getLength()) + "%";
   textPaint.getTextBounds(text.toCharArray(), 0, text.toCharArray().length, textRect);
   canvas.drawText(text, progressOffsetX + startX - textRect.right / 2, height / 2 - pbProgerssDrawable.getHeight() / 2 - pbPaint.getStrokeWidth() + textRect.bottom, textPaint);
   //我們啟動(dòng)一個(gè)線程,如果300毫秒進(jìn)度沒有更新,將畫布旋轉(zhuǎn)回來畫進(jìn)度提示圖片和文字
   if (progressOffsetX < pm.getLength()) postDelayed(rotateRunnable, 300);
   else toSucc();
   canvas.restore();
其中rotateRunnable的代碼如下



 //每隔一段時(shí)間刷新界面,如果進(jìn)度沒有更新,將畫布旋轉(zhuǎn)回來
 private Runnable rotateRunnable = new Runnable() {
  @Override
  public void run() {
   isRotate = true;
   invalidate();
  }
 };

4.當(dāng)進(jìn)度達(dá)到100%的時(shí)候,我們將進(jìn)度提示圖片縮放至消失,并且進(jìn)度背景執(zhí)行兩端向中間縮小動(dòng)畫,也是改變path的起始點(diǎn),代碼如下

 //下載進(jìn)度達(dá)到100時(shí),進(jìn)度提示圖片進(jìn)行縮放
 private void toSuccBitmapScale() {
  cancleValueAnimator(va_List);
  ValueAnimator va = ValueAnimator.ofFloat(1, 0);
  va.setInterpolator(new AccelerateInterpolator());
  va.setDuration(100);
  va.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
   @Override
   public void onAnimationUpdate(ValueAnimator animation) {
    bitmapScale = (Float) animation.getAnimatedValue();
    state = SUCCESS;
    invalidate();
   }
  });
  va.start();
  va.addListener(new MyAnimationListener() {
   @Override
   public void onAnimationEnd(Animator animation) {
    toSuccPathAnim();
   }
  });
  va_List.add(va);
 }

 //成功后進(jìn)度條縮放動(dòng)畫
 private void toSuccPathAnim() {
  cancleValueAnimator(va_List);
  ValueAnimator va = ValueAnimator.ofInt(0, (endX - startX) / 2);
  va.setInterpolator(new AccelerateInterpolator());
  va.setDuration(300);
  va.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
   @Override
   public void onAnimationUpdate(ValueAnimator animation) {
    transx = (int) animation.getAnimatedValue();
    state = SUCCESS;
    invalidate();
   }
  });
  va.start();
  va.addListener(new MyAnimationListener() {
   @Override
   public void onAnimationEnd(Animator animation) {
    toInstall();
   }
  });
  va_List.add(va);
 }

繪制代碼如下

   pbPath.reset();
   pbPath.moveTo(startX + transx, height / 2);//不斷的改變起點(diǎn)
   pbPath.lineTo(endX - transx, height / 2);//改變終點(diǎn)
   pm.setPath(pbPath, false);
   pm.getSegment(0, (endX - startX), pbPathSec, true);
   pm.getPosTan(endX - startX, POS, null);
   matrix.reset();
   matrix.preTranslate(POS[0] - pbProgerssDrawable.getWidth() / 2, POS[1] - pbProgerssDrawable.getHeight() - pbPaint.getStrokeWidth());
   matrix.postScale(bitmapScale, bitmapScale, POS[0], POS[1] - pbPaint.getStrokeWidth());
   canvas.drawPath(pbPath, pbUpdatePaint);//path縮放動(dòng)畫
   canvas.drawBitmap(pbProgerssDrawable, matrix, bitmapPaint);//bitmap縮放動(dòng)畫

5.最后就是顯示馬上安裝圖片動(dòng)畫了,一個(gè)簡(jiǎn)單的縮放

 //顯示馬上安裝圖片動(dòng)畫
 private void toInstall() {
  cancleValueAnimator(va_List);
  ValueAnimator va = ValueAnimator.ofInt(0, 1);
  va.setInterpolator(new LinearInterpolator());
  va.setDuration(400);
  va.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
   @Override
   public void onAnimationUpdate(ValueAnimator animation) {
    bitmapScale = animation.getAnimatedFraction();
    state = INSTALL;
    invalidate();
   }
  });
  va.start();
  va_List.add(va);
 }


  //繪制代碼如下
    matrix.reset();
    matrix.setScale(bitmapScale, bitmapScale);
    matrix.preTranslate(0, 0);
    matrix.postTranslate(width / 2 - succDrawable.getWidth() / 2 * bitmapScale, height / 2 - succDrawable.getHeight() / 2 * bitmapScale);
    canvas.drawBitmap(succDrawable, matrix, bitmapPaint);

回過頭來看看,其實(shí)當(dāng)我們把動(dòng)畫不斷的分解之后,發(fā)現(xiàn)其實(shí)每個(gè)動(dòng)畫并沒有那么難,我們這里用到的有path繪制及截取,getPosTan(獲取路徑上某點(diǎn)的坐標(biāo)及其切線的坐標(biāo)),利用Matrix做動(dòng)畫,使用屬性動(dòng)畫ValueAnimator。本篇還有好多功能沒有實(shí)現(xiàn),比如下載失敗動(dòng)畫,失敗后恢復(fù)至初始化動(dòng)畫,不過任何輪子都不一定能完全適合你,學(xué)習(xí)到知識(shí)之后自己造一個(gè)適合自己的才是最重要。

github地址:https://github.com/MrAllRight/BezierView


分享標(biāo)題:Android自定義Viewapp更新動(dòng)畫詳解
URL分享:http://www.xueling.net.cn/article/pjhdes.html

其他資訊

在線咨詢
服務(wù)熱線
服務(wù)熱線:028-86922220
TOP
主站蜘蛛池模板: 免费观看一区二区 | 亚洲av片不卡无码影视 | 午夜剧场韩 | 国产资源视频在线观看 | 国产一卡2卡3卡4卡新区乱码在 | 亚洲AV无码一区二区三区鸳鸯影院 | 九九爱国产 | 免费se99se | 色婷婷综合成人av | av片在线观看永久免费 | 亚洲国产主播一区 | 亚洲欧美成人A∨在线观看 亚洲一区二区福利视频 | 欧美大逼视频 | 美国一级黄色录像 | 亚洲一区二区三区精品中文字幕 | 亚洲国产va精品久久久不卡综合 | 国产精品美女久久久久久 | 国产亚洲人成a在线v网站 | 在线观看qvod | 国产一区二区三区在线视频观看 | 激情小说av| 国产在线1 | 欧美孕妇变态重口另类 | 欧美日韩精品一区二区久久 | 狠狠久久亚洲欧美专区 | 日本一区二区影视 | 网站一级片 | 亚洲精品乱码久久久久久久久久久久 | 中文字幕日韩三级 | 人妻系列无码专区无码中出 | 少妇扒开毛茸茸的b自慰 | 欧美大屁股xxxx高跟欧美黑人 | 1级片无码高清久久久 | 完美世界免费完整观看 | 日韩美国1级大片 | 国产精品一区二区在线免费观看 | 人人妻人人妻人人片色av | 国产精品日韩一区二区三区 | 最好的老师 | 久久久无码精品亚洲日韩 | 国产青草视频在线观看 |