編輯:關於Android編程
直播功能現在已經是一個很熱門的功能了,很多應用都會涉及到直播模塊,比如 花椒 NOW 還有辣媽幫。。等,最近因為項目需要也加入了直播功能。直播中有一個點贊的效果 ,今天我也按照自己的思路實現了一個這樣的點贊功能,效果如下:
簡單描述一下效果
1.產生一顆心
2.由下至上的曲線運動
3.開頭有一段放大效果
4.透明度漸變效果<喎?/kf/ware/vc/" target="_blank" class="keylink">vcD4NCjxwPsq1z9bS1MnP0Ke5+8nmvLC1vbXE1qrKtrXjPGJyIC8+DQrH+s/fuey8oyCjusr00NS2r7uto6uxtMj8tvvH+s/fy+O3qDxiciAvPg0K08nT2rXj1N7Qp7n71NrWsbKl1tC1xLPW0PjKsbzkysexyL3Ps6S1xDxiciAvPg0Ky/nS1NXiwO/KudPDtcTKx3N1cmZhY2V2aWV3IL/J0tTU2rmk1/fP37PM1tC75tbGdWk8YnIgLz4NCnVpu+bWxqO6c3VyZmFjZXZpZXc8L3A+DQo8cD64w9Cnufu1xLnsvKPUrdDNzbw8YnIgLz4NCjxpbWcgYWx0PQ=="這裡寫圖片描述" src="/uploadfile/Collfiles/20160905/20160905095858441.png" title="\" />
軌跡坐標點是通過屬性動畫 TypeEvaluator 生成的
private class BezierEvaluator implements TypeEvaluator{ 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); } }
接下來分享一下代碼的實現思路
由兩個類構成的 Zanbean ZanView
public class ZanBean { /**心的當前坐標*/ public Point point; /**移動動畫*/ private ValueAnimator moveAnim; /**放大動畫*/ private ValueAnimator zoomAnim; /**透明度*/ public int alpha=255;// /**心圖*/ private Bitmap bitmap; /**繪制bitmap的矩陣 用來做縮放和移動的*/ private Matrix matrix = new Matrix(); /**縮放系數*/ private float sf=0; /**產生隨機數*/ private Random random; public boolean isEnd=false;//是否結束 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()), new Point((random.nextInt(zanView.getWidth())), 0)); } public ZanBean(Context context,Bitmap bitmap,ZanView zanView) { random=new Random(); this.bitmap= bitmap; init(new Point(zanView.getWidth() / 2, zanView.getHeight()), 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(2500); 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 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{ 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); } } }
Zanbean
用來記錄心的軌跡 和 繪制的工作
這裡簡單介紹一下init方法
@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(2500); 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(); }
在創建對象的時候 屬性動畫會直接啟動。更符合場景,相當每個心丟進畫面就會自動跑起來,每個心都是獨立的個體
然後是ZanView 畫面繪制和呈現的主體
public class ZanView extends SurfaceView implements SurfaceHolder.Callback { private SurfaceHolder surfaceHolder; /**心的個數*/ private ArrayListzanBeen = new ArrayList<>(); private Paint p; /**負責繪制的工作線程*/ 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); /**設置畫布 背景透明*/ this.getHolder().setFormat(PixelFormat.TRANSLUCENT); surfaceHolder = getHolder(); surfaceHolder.addCallback(this); p = new Paint(); p.setAntiAlias(true); drawThread = new DrawThread(); } /**點贊動作 添加心的函數 控制畫面最大心的個數*/ 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(); /**繪制的線程 死循環 不斷的跑動*/ while (isRun) { Canvas canvas = null; try { synchronized (surfaceHolder) { canvas = surfaceHolder.lockCanvas(); /**清除畫面*/ canvas.drawColor(Color.TRANSPARENT, PorterDuff.Mode.CLEAR); boolean isEnd=true; /**對所有心進行遍歷繪制*/ for (int i = 0; i < zanBeen.size(); i++) { isEnd=zanBeen.get(i).isEnd; zanBeen.get(i).draw(canvas, p); } /**這裡做一個性能優化的動作,由於線程是死循環的 在沒有心需要的繪制的時候會結束線程*/ 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(); } 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();} } }
以上是ZanView的所有代碼 重要的地方都做了注釋 還是比較好懂的吧
為了驗證貝賽爾曲線
只要將這句話注釋就能看到每一幀的軌跡
/**清除畫面*/ canvas.drawColor(Color.TRANSPARENT, PorterDuff.Mode.CLEAR);
以上就是關於點贊 心動的效果 有什麼問題歡迎指出
移動大王卡怎麼購買、移動大王卡怎麼激活呢?下面小編分享一下移動大王卡購買鏈接,一起來看看吧。 移動大王卡怎麼購買? 通過山東移動掌廳申請,點擊&
Android用到的圖片資源一般指三種:png/jpg等位圖文體,.9文件,selector xml文件,在之前的開發中,都放在drawable目錄下,但使用最新的And
Android應用開發時,自定義控件時少不了和View的觸摸點擊事件打交道。針對View的事件分發原理,也看過網上的一些博客,但是看歸看,看了之後時間一長就又忘記了,因此
WebView中存在著兩種緩存:網頁數據緩存(存儲打開過的頁面及資源)、H5緩存(即appcache)。一、網頁緩存1、緩存構成/data/data/package_na