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

首頁 > 系統(tǒng) > Android > 正文

Android使用SurfaceView實(shí)現(xiàn)飄贊動畫

2019-10-22 18:13:35
字體:
供稿:網(wǎng)友

最近做直播項(xiàng)目,需要實(shí)現(xiàn)點(diǎn)贊動畫,一提起動畫就想到了使用View的屬性動畫,后來想了一下,那么多用戶點(diǎn)贊,會導(dǎo)致屏幕上出現(xiàn)很多View,開銷太大,一定會很卡,所以看主流主播軟件用什么方案解決的。

于是反編譯了映客apk,大概看了一下,它的點(diǎn)贊只用了一個(gè)SurfaceView,每個(gè)心都是實(shí)時(shí)畫到畫布上去的,這樣效率確實(shí)很高,再多的心也不怕了。思路有了,但是自己從頭到尾寫畢竟麻煩,后來上網(wǎng)查了是否有其他人已經(jīng)做好了呢?果然有現(xiàn)成的,思路很清晰,很簡潔,根據(jù)自己的需求改一改就好了。

前面說了一堆,主要想說明有些效果自己雖然沒做過,但是可以參考其他成熟產(chǎn)品是怎么做的,這樣會少走彎路,試想如果自己只用view屬性動畫,也實(shí)現(xiàn)了,豈不是卡的要死,最后還是要推倒重做的。

先看一下效果:

 

ZanBean類,每個(gè)ZanBean都要負(fù)責(zé)實(shí)時(shí)更新自己的位置、透明度等數(shù)據(jù)

 

import android.animation.TypeEvaluator; import android.animation.ValueAnimator; import android.annotation.TargetApi; import android.content.Context; import android.graphics.Bitmap; import android.graphics.BitmapFactory; import android.graphics.Canvas; import android.graphics.Matrix; import android.graphics.Paint; import android.graphics.Point; import android.os.Build;  import java.util.Random;  public class ZanBean {    /**    * 心的當(dāng)前坐標(biāo)    */   public Point point;   /**    * 移動動畫    */   private ValueAnimator moveAnim;   /**    * 放大動畫    */   private ValueAnimator zoomAnim;   /**    * 透明度    */   public int alpha = 255;//   /**    * 心圖    */   private Bitmap bitmap;   /**    * 繪制bitmap的矩陣 用來做縮放和移動的    */   private Matrix matrix = new Matrix();   /**    * 縮放系數(shù)    */   private float sf = 0;   /**    * 產(chǎn)生隨機(jī)數(shù)    */   private Random random;   public boolean isEnd = false;//是否結(jié)束    public ZanBean(Context context, int resId, ZanView zanView) {     random = new Random();     bitmap = BitmapFactory.decodeResource(context.getResources(), resId);     init(new Point(zanView.getWidth() / 2, zanView.getHeight()- bitmap.getHeight() / 2), new Point((random.nextInt(zanView.getWidth())), 0));   }     public ZanBean(Bitmap bitmap, ZanView zanView) {     random = new Random();     this.bitmap = bitmap;     //為了讓在起始坐標(biāo)點(diǎn)時(shí)顯示完整 需要減去bitmap.getHeight()/2     init(new Point(zanView.getWidth() / 2, zanView.getHeight() - bitmap.getHeight() / 2), new Point((random.nextInt(zanView.getWidth())), 0));   }    @TargetApi(Build.VERSION_CODES.HONEYCOMB)   private void init(final Point startPoint, Point endPoint) {     moveAnim = ValueAnimator.ofObject(new BezierEvaluator(new Point(random.nextInt(startPoint.x * 2), Math.abs(endPoint.y - startPoint.y) / 2)), startPoint, endPoint);     moveAnim.setDuration(1500);     moveAnim.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {       @Override       public void onAnimationUpdate(ValueAnimator animation) {         point = (Point) animation.getAnimatedValue();         alpha = (int) ((float) point.y / (float) startPoint.y * 255);       }     });     moveAnim.start();     zoomAnim = ValueAnimator.ofFloat(0, 1f).setDuration(700);     zoomAnim.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {       @Override       public void onAnimationUpdate(ValueAnimator animation) {         Float f = (Float) animation.getAnimatedValue();         sf = f.floatValue();       }     });     zoomAnim.start();   }  //  public void pause(){ //    if(moveAnim !=null&& moveAnim.isRunning()){ //      moveAnim.pause(); //    } //    if(zoomAnim !=null&& zoomAnim.isRunning()){ //      zoomAnim.pause(); //    } //  } // //  public void resume(){ //    if(moveAnim !=null&& moveAnim.isPaused()){ //      moveAnim.resume(); //    } //    if(zoomAnim !=null&& zoomAnim.isPaused()){ //      zoomAnim.resume(); //    } //  }    public void stop() {     if (moveAnim != null) {       moveAnim.cancel();       moveAnim = null;     }     if (zoomAnim != null) {       zoomAnim.cancel();       zoomAnim = null;     }   }    /**    * 主要繪制函數(shù)    */   public void draw(Canvas canvas, Paint p) {     if (bitmap != null && alpha > 0) {       p.setAlpha(alpha);       matrix.setScale(sf, sf, bitmap.getWidth() / 2, bitmap.getHeight() / 2);       matrix.postTranslate(point.x - bitmap.getWidth() / 2, point.y - bitmap.getHeight() / 2);       canvas.drawBitmap(bitmap, matrix, p);     } else {       isEnd = true;     }   }    /**    * 二次貝塞爾曲線    */   @TargetApi(Build.VERSION_CODES.HONEYCOMB)   private class BezierEvaluator implements TypeEvaluator<Point> {      private Point centerPoint;      public BezierEvaluator(Point centerPoint) {       this.centerPoint = centerPoint;     }      @Override     public Point evaluate(float t, Point startValue, Point endValue) {       int x = (int) ((1 - t) * (1 - t) * startValue.x + 2 * t * (1 - t) * centerPoint.x + t * t * endValue.x);       int y = (int) ((1 - t) * (1 - t) * startValue.y + 2 * t * (1 - t) * centerPoint.y + t * t * endValue.y);       return new Point(x, y);     }   } } 

ZanView代碼如下:SurfaceView,不斷將ZanBean畫到自己的畫布上。

 

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.util.AttributeSet; import android.view.SurfaceHolder; import android.view.SurfaceView;  import java.util.ArrayList;  public class ZanView extends SurfaceView implements SurfaceHolder.Callback {    private SurfaceHolder surfaceHolder;    /**    * 心的個(gè)數(shù)    */   private ArrayList<ZanBean> zanBeen = new ArrayList<>();   private Paint p;   /**    * 負(fù)責(zé)繪制的工作線程    */   private DrawThread drawThread;    public ZanView(Context context) {     this(context, null);   }    public ZanView(Context context, AttributeSet attrs) {     this(context, attrs, 0);   }    public ZanView(Context context, AttributeSet attrs, int defStyleAttr) {     super(context, attrs, defStyleAttr);     this.setZOrderOnTop(true);     /**設(shè)置畫布 背景透明*/     this.getHolder().setFormat(PixelFormat.TRANSLUCENT);     surfaceHolder = getHolder();     surfaceHolder.addCallback(this);     p = new Paint();     p.setAntiAlias(true);     drawThread = new DrawThread();   }    /**    * 點(diǎn)贊動作 添加心的函數(shù) 控制畫面最大心的個(gè)數(shù)    */   public void addZanXin(ZanBean zanBean) {     zanBeen.add(zanBean);     if (zanBeen.size() > 40) {       zanBeen.remove(0);     }     start();   }    @Override   public void surfaceCreated(SurfaceHolder holder) {     if (drawThread == null) {       drawThread = new DrawThread();     }     drawThread.start();   }    @Override   public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {    }    @Override   public void surfaceDestroyed(SurfaceHolder holder) {     if (drawThread != null) {       drawThread.isRun = false;       drawThread = null;     }   }    class DrawThread extends Thread {     boolean isRun = true;      @Override     public void run() {       super.run();       /**繪制的線程 死循環(huán) 不斷的跑動*/       while (isRun) {         Canvas canvas = null;         try {           synchronized (surfaceHolder) {             canvas = surfaceHolder.lockCanvas();             /**清除畫面*/             canvas.drawColor(Color.TRANSPARENT, PorterDuff.Mode.CLEAR);             boolean isEnd = true;              /**對所有心進(jìn)行遍歷繪制*/             for (int i = 0; i < zanBeen.size(); i++) {               isEnd = zanBeen.get(i).isEnd;               zanBeen.get(i).draw(canvas, p);             }             /**這里做一個(gè)性能優(yōu)化的動作,由于線程是死循環(huán)的 在沒有心需要的繪制的時(shí)候會結(jié)束線程*/             if (isEnd) {               isRun = false;               drawThread = null;             }           }         } catch (Exception e) {           e.printStackTrace();         } finally {           if (canvas != null) {             surfaceHolder.unlockCanvasAndPost(canvas);           }         }         try {           /**用于控制繪制幀率*/           Thread.sleep(10);         } catch (InterruptedException e) {           e.printStackTrace();         }       }     }   }    public void stop() {     if (drawThread != null) {  //      for (int i = 0; i < zanBeen.size(); i++) { //        zanBeen.get(i).pause(); //      }       for (int i = 0; i < zanBeen.size(); i++) {         zanBeen.get(i).stop();       }        drawThread.isRun = false;       drawThread = null;     }    }    public void start() {     if (drawThread == null) { //      for (int i = 0; i < zanBeen.size(); i++) { //        zanBeen.get(i).resume(); //      }       drawThread = new DrawThread();       drawThread.start();     }   } } 

調(diào)用方式:

public class TestActivity extends BaseActivity {   @Override   protected void onCreate(Bundle savedInstanceState) {     super.onCreate(savedInstanceState);     setContentView(R.layout.test_zan);     final ZanView zan = (ZanView) findViewById(R.id.zan_view);     zan.start();     findViewById(R.id.button).setOnClickListener(new View.OnClickListener() {       @Override       public void onClick(View v) {         ZanBean zanBean = new ZanBean(BitmapFactory.decodeResource(getResources(), R.drawable.ic_default_avatar), zan);         zan.addZanXin(zanBean);       }     });   } } 

以上就是本文的全部內(nèi)容,希望對大家的學(xué)習(xí)有所幫助,也希望大家多多支持VEVB武林網(wǎng)。


注:相關(guān)教程知識閱讀請移步到Android開發(fā)頻道。
發(fā)表評論 共有條評論
用戶名: 密碼:
驗(yàn)證碼: 匿名發(fā)表
主站蜘蛛池模板: 阿鲁科尔沁旗| 孙吴县| 信宜市| 晴隆县| 鸡东县| 嘉祥县| 宁化县| 临夏县| 太原市| 鄱阳县| 郯城县| 斗六市| 迁安市| 正宁县| 蒙自县| 益阳市| 溧水县| 司法| 镇远县| 乳山市| 定州市| 通州市| 平顶山市| 拜泉县| 大渡口区| 大连市| 广东省| 丽水市| 钟山县| 武清区| 乌兰浩特市| 溧水县| 孝义市| 出国| 武山县| 汉中市| 卢氏县| 九寨沟县| 肇源县| 北川| 云林县|