欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

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

 更新時(shí)間:2018年03月28日 14:57:15   作者:天空還是那么藍(lán)  
這篇文章主要為大家詳細(xì)介紹了Android如何使用SurfaceView實(shí)現(xiàn)飄贊動(dòng)畫(huà),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下

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

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

前面說(shuō)了一堆,主要想說(shuō)明有些效果自己雖然沒(méi)做過(guò),但是可以參考其他成熟產(chǎn)品是怎么做的,這樣會(huì)少走彎路,試想如果自己只用view屬性動(dòng)畫(huà),也實(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; 
 /** 
  * 移動(dòng)動(dòng)畫(huà) 
  */ 
 private ValueAnimator moveAnim; 
 /** 
  * 放大動(dòng)畫(huà) 
  */ 
 private ValueAnimator zoomAnim; 
 /** 
  * 透明度 
  */ 
 public int alpha = 255;// 
 /** 
  * 心圖 
  */ 
 private Bitmap bitmap; 
 /** 
  * 繪制bitmap的矩陣 用來(lái)做縮放和移動(dòng)的 
  */ 
 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畫(huà)到自己的畫(huà)布上。

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è)置畫(huà)布 背景透明*/ 
  this.getHolder().setFormat(PixelFormat.TRANSLUCENT); 
  surfaceHolder = getHolder(); 
  surfaceHolder.addCallback(this); 
  p = new Paint(); 
  p.setAntiAlias(true); 
  drawThread = new DrawThread(); 
 } 
 
 /** 
  * 點(diǎn)贊動(dòng)作 添加心的函數(shù) 控制畫(huà)面最大心的個(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) 不斷的跑動(dòng)*/ 
   while (isRun) { 
    Canvas canvas = null; 
    try { 
     synchronized (surfaceHolder) { 
      canvas = surfaceHolder.lockCanvas(); 
      /**清除畫(huà)面*/ 
      canvas.drawColor(Color.TRANSPARENT, PorterDuff.Mode.CLEAR); 
      boolean isEnd = true; 
 
      /**對(duì)所有心進(jìn)行遍歷繪制*/ 
      for (int i = 0; i < zanBeen.size(); i++) { 
       isEnd = zanBeen.get(i).isEnd; 
       zanBeen.get(i).draw(canvas, p); 
      } 
      /**這里做一個(gè)性能優(yōu)化的動(dòng)作,由于線程是死循環(huán)的 在沒(méi)有心需要的繪制的時(shí)候會(huì)結(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); 
   } 
  }); 
 } 
} 

以上就是本文的全部?jī)?nèi)容,希望對(duì)大家的學(xué)習(xí)有所幫助,也希望大家多多支持腳本之家。

相關(guān)文章

  • Kotlin中?和!!的區(qū)別詳細(xì)對(duì)比

    Kotlin中?和!!的區(qū)別詳細(xì)對(duì)比

    這篇文章主要給大家介紹了關(guān)于Kotlin中?和!!區(qū)別的相關(guān)資料,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧
    2021-05-05
  • Android中LayoutAnimal的使用方法詳解

    Android中LayoutAnimal的使用方法詳解

    這篇文章給大家講講酷炫的動(dòng)畫(huà)成員LayoutAnimal,文章通過(guò)一個(gè)實(shí)例給大家詳細(xì)介紹了Android中LayoutAnimal的使用方法,感興趣的小伙伴可以自己動(dòng)手試一試
    2023-09-09
  • Android Studio下無(wú)線調(diào)試的方法

    Android Studio下無(wú)線調(diào)試的方法

    這篇文章主要為大家詳細(xì)介紹了Android Studio平臺(tái)下無(wú)線調(diào)試的方法,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2018-05-05
  • Android實(shí)現(xiàn)簡(jiǎn)單購(gòu)物車

    Android實(shí)現(xiàn)簡(jiǎn)單購(gòu)物車

    這篇文章主要為大家詳細(xì)介紹了Android實(shí)現(xiàn)簡(jiǎn)單購(gòu)物車,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2022-06-06
  • android實(shí)現(xiàn)通知欄下載更新app示例

    android實(shí)現(xiàn)通知欄下載更新app示例

    這篇文章主要介紹了android實(shí)現(xiàn)通知欄下載更新app示例,需要的朋友可以參考下
    2014-03-03
  • Android  LayoutInflater.inflate()詳解及分析

    Android LayoutInflater.inflate()詳解及分析

    這篇文章主要介紹了Android LayoutInflater.inflate()詳解及分析的相關(guān)資料,需要的朋友可以參考下
    2017-01-01
  • 詳解Android Studio3.5及使用AndroidX的一些坑

    詳解Android Studio3.5及使用AndroidX的一些坑

    這篇文章主要介紹了詳解Android Studio3.5及使用AndroidX的一些坑,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧
    2019-11-11
  • Android開(kāi)發(fā)筆記之:復(fù)寫(xiě)按鈕方法

    Android開(kāi)發(fā)筆記之:復(fù)寫(xiě)按鈕方法

    本篇文章是對(duì)Android中復(fù)寫(xiě)按鈕方法進(jìn)行了詳細(xì)的分析介紹,需要的朋友參考下
    2013-05-05
  • 使用Android的OkHttp包實(shí)現(xiàn)基于HTTP協(xié)議的文件上傳下載

    使用Android的OkHttp包實(shí)現(xiàn)基于HTTP協(xié)議的文件上傳下載

    OkHttp(GitHub主頁(yè)https://github.com/square/okhttp)是近來(lái)人氣攀升的一款安卓第三方HTTP包,這里我們來(lái)講解一下如何使用Android的OkHttp包實(shí)現(xiàn)基于HTTP協(xié)議的文件上傳下載:
    2016-07-07
  • android 設(shè)置wallpaper的操作方法

    android 設(shè)置wallpaper的操作方法

    下面小編就為大家?guī)?lái)一篇android 設(shè)置wallpaper的操作方法。小編覺(jué)得挺不錯(cuò)的,現(xiàn)在就分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧
    2017-08-08

最新評(píng)論