国产探花免费观看_亚洲丰满少妇自慰呻吟_97日韩有码在线_资源在线日韩欧美_一区二区精品毛片,辰东完美世界有声小说,欢乐颂第一季,yy玄幻小说排行榜完本

首頁 > 系統 > Android > 正文

Android 使用 Path 實現搜索動態加載動畫效果

2019-10-21 21:41:36
字體:
來源:轉載
供稿:網友

今天實現一個搜索動態加載數據的動畫效果,還是先看效果吧,用文字描述干巴巴的,看圖說話什么都明白了,

Android,Path,動態加載動畫

實現這個就是使用Path中的getSegment()不斷的去改變它截取片段的start和stop,再結合動畫,今天就分步驟實現它,看完以后你也會覺的不是很難,只是沒想到這么實現而已,所以要多見識,所謂眼界決定你的高度,還是延續我寫博客的習慣,一步步分析,第一步就是繪制如下圖:

Android,Path,動態加載動畫

如果單純的繪制這個圖很簡單很簡單的,繪制一個圓,然后再繪制一根線就搞定,但是要考慮這里的效果,就不能這么干了,如果你看了上面的gif圖就知道,其實這是2個同心圓,然后前一個path的起點和后一個path的起點相連接就是形成一條直線了,但是path中的圖形內容也就是這個圓是怎么繪制出來的呢?如果是繪制圓的話,上面的線起點和終點位置怎么去計算,這是個問題,但是我們繪制圓還可以使用繪制橢圓的形式也是可以繪制達到圓的效果,從45度開始繪制一個圓,是不是這個線的起點搞定了,分析圖如下:

Android,Path,動態加載動畫

那么好,根據上面的分析開始寫代碼繪制出一個靜態的搜索圖:

 

package com.tuya;import android.content.Context;import android.graphics.Canvas;import android.graphics.Color;import android.graphics.Paint;import android.graphics.Path;import android.graphics.PathMeasure;import android.graphics.RectF;import android.util.AttributeSet;import android.view.View;/** * Created by admin on 2016/12/17. */public class DynamicSearchView2 extends View { private Paint paint; private int width;//view的寬度 private int height;//view的高度 private Path searchPath; private Path circlePath; private float BigCircleRectWidth;//搜索圓對應的外切正方形邊長 private PathMeasure pathMeasure; private float[] pos; public DynamicSearchView2(Context context) {  this(context,null); } public DynamicSearchView2(Context context, AttributeSet attrs) {  this(context, attrs,0); } public DynamicSearchView2(Context context, AttributeSet attrs, int defStyleAttr) {  super(context, attrs, defStyleAttr);  init(); } private void init() {  paint = new Paint();  paint.setAntiAlias(true);  paint.setStrokeWidth(3);  paint.setColor(Color.WHITE);  paint.setStyle(Paint.Style.STROKE); } @Override protected void onSizeChanged(int w, int h, int oldw, int oldh) {  super.onSizeChanged(w, h, oldw, oldh);  width = w;  height = h;  initPath(); } /**  * 初始化path  */ private void initPath() {  searchPath = new Path();  circlePath = new Path();  if(width>height){//長方形   BigCircleRectWidth = height;  }else if(width<height){   BigCircleRectWidth = width;  }else{   BigCircleRectWidth = width;  }  float smallbordWidth =BigCircleRectWidth/8;  RectF searchRect = new RectF(-smallbordWidth,-smallbordWidth,smallbordWidth,smallbordWidth);  searchPath.addArc(searchRect,45,360);  float bigBordWidth = smallbordWidth*2;  RectF circleRect = new RectF(-bigBordWidth,-bigBordWidth,bigBordWidth,bigBordWidth);  circlePath.addArc(circleRect,45,-360);  pathMeasure = new PathMeasure(circlePath,false);  pos = new float[2];  pathMeasure.getPosTan(0,pos,null);  searchPath.lineTo(pos[0],pos[1]); } @Override protected void onDraw(Canvas canvas) {  super.onDraw(canvas);  canvas.translate(width/2,height/2);//平移畫布把這個view的中心點當做原點  canvas.drawPath(searchPath,paint);  canvas.drawPath(circlePath,paint); }}

效果圖:

Android,Path,動態加載動畫

本來這個外圓是不需要draw上去的,我在這繪制上去只是告訴你這二個圓是有一定的聯系,哪為什么這根線是這樣的呢?我們在繪制這個圓的時候是從45度開始繪制360剛好是一周,形成了一個圓,現在做個測試不要360,就寫個330度,效果如下:

Android,Path,動態加載動畫

這個時候你會發現這條線是對的,導致問題其實是這樣的,如圖分析:

Android,Path,動態加載動畫

把繪制橢圓的關鍵代碼:

searchPath.addArc(searchRect,45,358);

circlePath.addArc(circleRect,45,-358);

不要寫成360,改為358試試,效果圖:

Android,Path,動態加載動畫

發現這線是不是正常了,至于外面的圓還有點缺口,第一你可以把358改成359應該沒事了,還有就是我們其實真實的效果并不需要這個外面的圓,所以不改也沒事,那么好,第一步算是完成了,現在想想第二步怎么實現,先把第二步的效果用gif展示看下,不然光想沒思路,就像你看美女,第一眼看那,是吧,就不多說了!要有畫面感,

Android,Path,動態加載動畫

還是畫布分析:

Android,Path,動態加載動畫

哪我們只要改變startD這個離起始點的位置值就ok,當然有很多種方法,但是Android中基本上都是使用值動畫,ok,根據這個思路實現這個第二步邏輯:

package com.tuya;import android.animation.Animator;import android.animation.ValueAnimator;import android.content.Context;import android.graphics.Canvas;import android.graphics.Color;import android.graphics.Paint;import android.graphics.Path;import android.graphics.PathMeasure;import android.graphics.RectF;import android.util.AttributeSet;import android.view.View;/** * Created by admin on 2016/12/17. */public class DynamicSearchView2 extends View { private Paint paint; private int width;//view的寬度 private int height;//view的高度 private Path searchPath; private Path circlePath; private float BigCircleRectWidth;//搜索圓對應的外切正方形邊長 private PathMeasure pathMeasure; private float[] pos; private float animPercent;// private ValueAnimator serchStartAnim; private long animDuration = 2000;//動畫時間 public DynamicSearchView2(Context context) {  this(context,null); } public DynamicSearchView2(Context context, AttributeSet attrs) {  this(context, attrs,0); } public DynamicSearchView2(Context context, AttributeSet attrs, int defStyleAttr) {  super(context, attrs, defStyleAttr);  init(); } private void init() {  initPaint();  initAnim();  initAnimListener();  startAnim(); } /**  * 開始執行動畫  */ private void startAnim() {  serchStartAnim.start(); } /**  * 動畫監聽  */ private void initAnimListener() {  serchStartAnim.addUpdateListener(new ValueAnimator.AnimatorUpdateListener(){   @Override   public void onAnimationUpdate(ValueAnimator valueAnimator) {     //獲取動畫在單位時間內,每次執行的值    animPercent = (float) valueAnimator.getAnimatedValue();    invalidate();   }  }); } /**  * 初始化動畫  */ private void initAnim() {  serchStartAnim = ValueAnimator.ofFloat(0,1).setDuration(animDuration); } /**  * 初始化畫筆  */ private void initPaint() {  paint = new Paint();  paint.setAntiAlias(true);  paint.setStrokeWidth(3);  paint.setColor(Color.WHITE);  paint.setStyle(Paint.Style.STROKE); } @Override protected void onSizeChanged(int w, int h, int oldw, int oldh) {  super.onSizeChanged(w, h, oldw, oldh);  width = w;  height = h;  initPath(); } /**  * 初始化path  */ private void initPath() {  searchPath = new Path();  circlePath = new Path();  if(width>height){//長方形   BigCircleRectWidth = height;  }else if(width<height){   BigCircleRectWidth = width;  }else{   BigCircleRectWidth = width;  }  float smallbordWidth =BigCircleRectWidth/8;  RectF searchRect = new RectF(-smallbordWidth,-smallbordWidth,smallbordWidth,smallbordWidth);  searchPath.addArc(searchRect,45,358);  float bigBordWidth = smallbordWidth*2;  RectF circleRect = new RectF(-bigBordWidth,-bigBordWidth,bigBordWidth,bigBordWidth);  circlePath.addArc(circleRect,45,-358);  pathMeasure = new PathMeasure(circlePath,false);  pos = new float[2];  pathMeasure.getPosTan(0,pos,null);  searchPath.lineTo(pos[0],pos[1]); } @Override protected void onDraw(Canvas canvas) {  super.onDraw(canvas);   canvas.translate(width/2,height/2);//平移畫布把這個view的中心點當做原點   drawSearch(canvas); } private void drawSearch(Canvas canvas) {  Path dst = new Path();  pathMeasure.setPath(searchPath,false);  pathMeasure.getSegment(pathMeasure.getLength()*animPercent,pathMeasure.getLength(),dst,true);  canvas.drawPath(searchPath,paint); }}

效果:

Android,Path,動態加載動畫

現在還我們效果還差外圓的大圓的效果了,那么大圓是在小圓動畫執行完畢后再去做旋轉效果的,那好,我們只要監聽動畫就可以,畫圖:

package com.tuya;import android.animation.Animator;import android.animation.ValueAnimator;import android.content.Context;import android.graphics.Canvas;import android.graphics.Color;import android.graphics.Paint;import android.graphics.Path;import android.graphics.PathMeasure;import android.graphics.RectF;import android.util.AttributeSet;import android.view.View;/** * Created by admin on 2016/12/17. */public class DynamicSearchView2 extends View { private static final String TAG = "DynamicSearchView2"; private Paint paint; private int width;//view的寬度 private int height;//view的高度 private Path searchPath; private Path circlePath; private float BigCircleRectWidth;//搜索圓對應的外切正方形邊長 private PathMeasure pathMeasure; private float[] pos; private float animPercent;// private ValueAnimator serchStartAnim; private ValueAnimator bigCircleAnim;//外面大圓運動的動畫 private long animDuration = 2000;//動畫時間 private int drawTag = 1;//區分是繪制搜索框還是外層圓 public DynamicSearchView2(Context context) {  this(context,null); } public DynamicSearchView2(Context context, AttributeSet attrs) {  this(context, attrs,0); } public DynamicSearchView2(Context context, AttributeSet attrs, int defStyleAttr) {  super(context, attrs, defStyleAttr);  init(); } private void init() {  initPaint();  initAnim();  initAnimListener();  startAnim(); } /**  * 開始執行動畫  */ private void startAnim() {  drawTag = 1;  serchStartAnim.start();  invalidate(); } /**  * 開啟大圓執行動畫  */ public void startBigCirCleAnim(){  serchStartAnim.removeAllUpdateListeners();//把上一個動畫監聽移除 以免總成詭異的bug  bigCircleAnim.start();  drawTag = 2; } /**  * 動畫監聽  */ private void initAnimListener() {  serchStartAnim.addListener(new Animator.AnimatorListener() {   @Override   public void onAnimationStart(Animator animator) {   }   @Override   public void onAnimationEnd(Animator animator) {    startBigCirCleAnim();   }   @Override   public void onAnimationCancel(Animator animator) {   }   @Override   public void onAnimationRepeat(Animator animator) {   }  });  serchStartAnim.addUpdateListener(new ValueAnimator.AnimatorUpdateListener(){   @Override   public void onAnimationUpdate(ValueAnimator valueAnimator) {    //獲取動畫在單位時間內,每次執行的值    animPercent = (float) valueAnimator.getAnimatedValue();    invalidate();   }  });  bigCircleAnim.addUpdateListener(new ValueAnimator.AnimatorUpdateListener(){   @Override   public void onAnimationUpdate(ValueAnimator valueAnimator) {    //獲取動畫在單位時間內,每次執行的值    animPercent = (float) valueAnimator.getAnimatedValue();    invalidate();   }  }); } /**  * 初始化動畫  */ private void initAnim() {  bigCircleAnim = ValueAnimator.ofFloat(0,1).setDuration(animDuration);  serchStartAnim = ValueAnimator.ofFloat(0,1).setDuration(animDuration); } /**  * 初始化畫筆  */ private void initPaint() {  paint = new Paint();  paint.setAntiAlias(true);  paint.setStrokeWidth(3);  paint.setColor(Color.WHITE);  paint.setStyle(Paint.Style.STROKE); } @Override protected void onSizeChanged(int w, int h, int oldw, int oldh) {  super.onSizeChanged(w, h, oldw, oldh);  width = w;  height = h;  initPath(); } /**  * 初始化path  */ private void initPath() {  searchPath = new Path();  circlePath = new Path();  if(width>height){//長方形   BigCircleRectWidth = height;  }else if(width<height){   BigCircleRectWidth = width;  }else{   BigCircleRectWidth = width;  }  float smallbordWidth =BigCircleRectWidth/8;  RectF searchRect = new RectF(-smallbordWidth,-smallbordWidth,smallbordWidth,smallbordWidth);  searchPath.addArc(searchRect,45,358);  float bigBordWidth = smallbordWidth*2;  RectF circleRect = new RectF(-bigBordWidth,-bigBordWidth,bigBordWidth,bigBordWidth);  circlePath.addArc(circleRect,45,-358);  pathMeasure = new PathMeasure(circlePath,false);  pos = new float[2];  pathMeasure.getPosTan(0,pos,null);  searchPath.lineTo(pos[0],pos[1]); } @Override protected void onDraw(Canvas canvas) {  super.onDraw(canvas);  canvas.translate(width/2,height/2);//平移畫布把這個view的中心點當做原點  drawSearch(canvas); } private void drawSearch(Canvas canvas) {  if(drawTag==1){   drawSearchGraph(canvas);  }else if(drawTag==2){   drawBigCircleGraph(canvas);  } } /**  * 繪制外層大圓  * @param canvas  */ private void drawBigCircleGraph(Canvas canvas) {  pathMeasure.setPath(circlePath, false);  Path dst2 = new Path();  float stop = pathMeasure.getLength() * animPercent;  float start = (float) (stop - ((0.5 - Math.abs(animPercent - 0.5)) * 200f));  pathMeasure.getSegment(start, stop, dst2, true);  canvas.drawPath(dst2, paint); } /**  * 繪制搜索框  * @param canvas  */ private void drawSearchGraph(Canvas canvas) {  pathMeasure.setPath(searchPath,false);  Path dst = new Path();  pathMeasure.getSegment(pathMeasure.getLength()*animPercent,pathMeasure.getLength(),dst,true);  canvas.drawPath(dst,paint); }}

效果:

Android,Path,動態加載動畫

發現轉一圈就到頭了,如果有特定的需求肯定是要控制整個轉圈的圈數,如果是網絡加載的話,除非網絡特別的好,先不管了,因為等下還要寫周報,也是很痛苦的

現在還差最后一步就是大圓的運動完后要繪制搜索框出來,其實這個和第一步效果剛好是相關的,

 

package com.tuya;import android.animation.Animator;import android.animation.ValueAnimator;import android.content.Context;import android.graphics.Canvas;import android.graphics.Color;import android.graphics.Paint;import android.graphics.Path;import android.graphics.PathMeasure;import android.graphics.RectF;import android.util.AttributeSet;import android.view.View;/** * Created by admin on 2016/12/17. */public class DynamicSearchView2 extends View { private static final String TAG = "DynamicSearchView2"; private Paint paint; private int width;//view的寬度 private int height;//view的高度 private Path searchPath; private Path circlePath; private float BigCircleRectWidth;//搜索圓對應的外切正方形邊長 private PathMeasure pathMeasure; private float[] pos; private float animPercent;// private ValueAnimator serchStartAnim; private ValueAnimator bigCircleAnim;//外面大圓運動的動畫 private ValueAnimator startDrawSearchAnim;//最后一步繪制搜索框 private long animDuration = 2000;//動畫時間 private int drawTag = 1;//區分是繪制搜索框還是外層圓 public DynamicSearchView2(Context context) {  this(context,null); } public DynamicSearchView2(Context context, AttributeSet attrs) {  this(context, attrs,0); } public DynamicSearchView2(Context context, AttributeSet attrs, int defStyleAttr) {  super(context, attrs, defStyleAttr);  init(); } private void init() {  initPaint();  initAnim();  initAnimListener();  startAnim(); } /**  * 開始執行動畫  */ private void startAnim() {  drawTag = 1;  serchStartAnim.start();  invalidate(); } /**  * 開啟大圓執行動畫  */ public void startBigCirCleAnim(){  serchStartAnim.removeAllUpdateListeners();//把上一個動畫監聽移除 以免總成詭異的bug  bigCircleAnim.start();  drawTag = 2; } /**  * 最后繪制搜索框的動畫  */ public void drawSearchAanim(){  bigCircleAnim.removeAllUpdateListeners();//把上一個動畫監聽移除 以免總成詭異的bug  startDrawSearchAnim.start();  drawTag = 3; } /**  * 動畫監聽  */ private void initAnimListener() {  bigCircleAnim.addListener(new Animator.AnimatorListener() {   @Override   public void onAnimationStart(Animator animator) {   }   @Override   public void onAnimationEnd(Animator animator) {    drawSearchAanim();   }   @Override   public void onAnimationCancel(Animator animator) {   }   @Override   public void onAnimationRepeat(Animator animator) {   }  });  serchStartAnim.addUpdateListener(new ValueAnimator.AnimatorUpdateListener(){   @Override   public void onAnimationUpdate(ValueAnimator valueAnimator) {    //獲取動畫在單位時間內,每次執行的值    animPercent = (float) valueAnimator.getAnimatedValue();    invalidate();   }  });  serchStartAnim.addListener(new Animator.AnimatorListener() {   @Override   public void onAnimationStart(Animator animator) {   }   @Override   public void onAnimationEnd(Animator animator) {    startBigCirCleAnim();   }   @Override   public void onAnimationCancel(Animator animator) {   }   @Override   public void onAnimationRepeat(Animator animator) {   }  });  serchStartAnim.addUpdateListener(new ValueAnimator.AnimatorUpdateListener(){   @Override   public void onAnimationUpdate(ValueAnimator valueAnimator) {    //獲取動畫在單位時間內,每次執行的值    animPercent = (float) valueAnimator.getAnimatedValue();    invalidate();   }  });  bigCircleAnim.addUpdateListener(new ValueAnimator.AnimatorUpdateListener(){   @Override   public void onAnimationUpdate(ValueAnimator valueAnimator) {    //獲取動畫在單位時間內,每次執行的值    animPercent = (float) valueAnimator.getAnimatedValue();    invalidate();   }  });  startDrawSearchAnim .addUpdateListener(new ValueAnimator.AnimatorUpdateListener(){   @Override   public void onAnimationUpdate(ValueAnimator valueAnimator) {    //獲取動畫在單位時間內,每次執行的值    animPercent = (float) valueAnimator.getAnimatedValue();    invalidate();   }  }); } /**  * 初始化動畫  */ private void initAnim() {  bigCircleAnim = ValueAnimator.ofFloat(0,1).setDuration(animDuration);  serchStartAnim = ValueAnimator.ofFloat(0,1).setDuration(animDuration);  startDrawSearchAnim = ValueAnimator.ofFloat(1,0).setDuration(animDuration); } /**  * 初始化畫筆  */ private void initPaint() {  paint = new Paint();  paint.setAntiAlias(true);  paint.setStrokeWidth(6);  paint.setColor(Color.WHITE);  paint.setStyle(Paint.Style.STROKE); } @Override protected void onSizeChanged(int w, int h, int oldw, int oldh) {  super.onSizeChanged(w, h, oldw, oldh);  width = w;  height = h;  initPath(); } /**  * 初始化path  */ private void initPath() {  searchPath = new Path();  circlePath = new Path();  if(width>height){//長方形   BigCircleRectWidth = height;  }else if(width<height){   BigCircleRectWidth = width;  }else{   BigCircleRectWidth = width;  }  float smallbordWidth =BigCircleRectWidth/8;  RectF searchRect = new RectF(-smallbordWidth,-smallbordWidth,smallbordWidth,smallbordWidth);  searchPath.addArc(searchRect,45,358);  float bigBordWidth = smallbordWidth*2;  RectF circleRect = new RectF(-bigBordWidth,-bigBordWidth,bigBordWidth,bigBordWidth);  circlePath.addArc(circleRect,45,-358);  pathMeasure = new PathMeasure(circlePath,false);  pos = new float[2];  pathMeasure.getPosTan(0,pos,null);  searchPath.lineTo(pos[0],pos[1]); } @Override protected void onDraw(Canvas canvas) {  super.onDraw(canvas);  canvas.translate(width/2,height/2);//平移畫布把這個view的中心點當做原點  drawSearch(canvas); } private void drawSearch(Canvas canvas) {  if(drawTag==1){   drawSearchGraph(canvas);  }else if(drawTag==2){   drawBigCircleGraph(canvas);  }else if(drawTag==3){   drawSearchBox(canvas);  } } /**  * 最后一步繪制搜索框 從終點到起點  * @param canvas  */ private void drawSearchBox(Canvas canvas) {  pathMeasure.setPath(searchPath, false);  Path dst3 = new Path();  pathMeasure.getSegment(pathMeasure.getLength() * animPercent, pathMeasure.getLength(), dst3, true);  canvas.drawPath(dst3, paint); } /**  * 繪制外層大圓  * @param canvas  */ private void drawBigCircleGraph(Canvas canvas) {  pathMeasure.setPath(circlePath, false);  Path dst2 = new Path();  float stop = pathMeasure.getLength() * animPercent;  float start = (float) (stop - ((0.5 - Math.abs(animPercent - 0.5)) * 200f));  pathMeasure.getSegment(start, stop, dst2, true);  canvas.drawPath(dst2, paint); } /**  * 繪制搜索框  * @param canvas  */ private void drawSearchGraph(Canvas canvas) {  pathMeasure.setPath(searchPath,false);  Path dst = new Path();  pathMeasure.getSegment(pathMeasure.getLength()*animPercent,pathMeasure.getLength(),dst,true);  canvas.drawPath(dst,paint); }}

效果:

Android,Path,動態加載動畫

github: https://github.com/zhouguizhi/PathSearch

總結

以上所述是小編給大家介紹的Android 使用 Path 實現搜索動態加載動畫效果,希望對大家有所幫助,如果大家有任何疑問請給我留言,小編會及時回復大家的。在此也非常感謝大家對VEVB武林網網站的支持!


注:相關教程知識閱讀請移步到Android開發頻道。
發表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發表
主站蜘蛛池模板: 平阳县| 凉山| 麻阳| 曲阜市| 呈贡县| 平遥县| 新乐市| 阿拉善右旗| 临颍县| 晋江市| 东乡县| 轮台县| 依安县| 隆回县| 百色市| 安仁县| 德保县| 临澧县| 金山区| 历史| 延川县| 崇阳县| 曲阳县| 昌平区| 彩票| 湄潭县| 龙游县| 盘山县| 全椒县| 河池市| 腾冲县| 奈曼旗| 确山县| 周至县| 五原县| 和田县| 亳州市| 淮北市| 古田县| 金川县| 峨边|