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

Android自定義View實現(xiàn)直播點贊特效

 更新時間:2020年07月29日 13:04:14   作者:愛碼士_yan  
這篇文章主要為大家詳細介紹了Android自定義View實現(xiàn)直播點贊特效,文中示例代碼介紹的非常詳細,具有一定的參考價值,感興趣的小伙伴們可以參考一下

由于開發(fā)的需要,需要開發(fā)類似直播點贊特效的需求,于是自定義View來實現(xiàn)這種效果

案例圖:

1.自定義View

import android.animation.Animator;
import android.animation.AnimatorSet;
import android.animation.ObjectAnimator;
import android.animation.TypeEvaluator;
import android.animation.ValueAnimator;
import android.content.Context;
import android.graphics.PointF;
import android.graphics.drawable.Drawable;
import android.util.AttributeSet;
import android.view.View;
import android.view.animation.AccelerateDecelerateInterpolator;
import android.view.animation.AccelerateInterpolator;
import android.view.animation.DecelerateInterpolator;
import android.view.animation.Interpolator;
import android.view.animation.LinearInterpolator;
import android.widget.ImageView;
import android.widget.RelativeLayout;
import com.xinrui.ndkapp.R;
import java.util.Random;

/**
 * Created by liuyong
 * Data: 2017/8/8
 * Github:https://github.com/MrAllRight
 * 直播點贊view
 */

public class GivePraiseView extends RelativeLayout {
 private RelativeLayout.LayoutParams layoutParams;//圖片布局參數(shù)
 private PointF mPointF0, mPointF1, mPointF2, mPointF3;//通過3階貝塞爾曲線控制圖片的移動軌跡
 private int mScreenWidth, mScreenHeight;//屏幕寬高
 private Drawable[] mImageDrawables;//加載點贊紅心圖片,紅黃藍
 private int mDrawableWidth, mDrawableHeight;//圖片的寬高
 private Random mRandom = new Random();
 private int count = 0;
 private Interpolator[] interpolators = new Interpolator[4];

 public GivePraiseView(Context context) {
  super(context);
  init();
 }

 public GivePraiseView(Context context, AttributeSet attrs, int defStyleAttr) {
  super(context, attrs, defStyleAttr);
  init();
 }

 public GivePraiseView(Context context, AttributeSet attrs) {
  super(context, attrs);
  init();
 }

 @Override
 protected void onSizeChanged(int w, int h, int oldw, int oldh) {
  super.onSizeChanged(w, h, oldw, oldh);
  mScreenHeight = h;
  mScreenWidth = w;
 }

 //初始化drawable,layoutParams
 private void init() {
  mImageDrawables = new Drawable[4];
  mImageDrawables[0] = getResources().getDrawable(R.drawable.pl_blue);
  mImageDrawables[1] = getResources().getDrawable(R.drawable.pl_red);
  mImageDrawables[2] = getResources().getDrawable(R.drawable.pl_yellow);
  mImageDrawables[3] = getResources().getDrawable(R.drawable.pl_red);
  // 插值器
  interpolators[0] = new AccelerateDecelerateInterpolator(); // 在動畫開始與結(jié)束的地方速率改變比較慢,在中間的時候加速
  interpolators[1] = new AccelerateInterpolator(); // 在動畫開始的地方速率改變比較慢,然后開始加速
  interpolators[2] = new DecelerateInterpolator(); // 在動畫開始的地方快然后慢
  interpolators[3] = new LinearInterpolator(); // 以常量速率改變
  mDrawableWidth = mImageDrawables[0].getIntrinsicWidth();
  mDrawableHeight = mImageDrawables[0].getIntrinsicHeight();
  layoutParams = new LayoutParams(50, 50);
  layoutParams.addRule(ALIGN_PARENT_BOTTOM, TRUE);
  layoutParams.addRule(ALIGN_PARENT_RIGHT, TRUE);
  layoutParams.setMargins(0, 0, 60, 60);//放置在屏幕的右下角
  //這里為了演示我們現(xiàn)在布局初始化的時候,放置一個imageview,顏色隨機,設(shè)置點擊屏幕出現(xiàn)點贊效果
  ImageView iv = new ImageView(getContext());
  iv.setLayoutParams(layoutParams);
  iv.setImageDrawable(mImageDrawables[0]);
  addView(iv);
  this.setOnClickListener(new OnClickListener() {
   @Override
   public void onClick(View v) {
    for(int i=0;i<10;i++) {
     addGivePraiseImg(count);
     count++;
     if (count == 4) count = 0;
    }
   }
  });
 }

 //點擊圖片是添加imageview到布局中,并添加動畫
 private void addGivePraiseImg(int count) {
  final ImageView givepraiseImg = new ImageView(getContext());
  givepraiseImg.setLayoutParams(layoutParams);
  givepraiseImg.setImageDrawable(mImageDrawables[count]);
  addView(givepraiseImg);
  addAnimator(givepraiseImg);//添加動畫效果,動畫分兩部分,第一部分是產(chǎn)生圖片時縮放和透明度,第二部是移動圖片再進行透明度變化
 }

 private void addAnimator(final ImageView imageView) {
  //點擊的時候,讓圖片經(jīng)過放大,縮放效果,之后再開始沿著貝塞爾曲線的軌跡移動
  ObjectAnimator alpha = ObjectAnimator.ofFloat(imageView, "alpha", 0.3f, 1f);
  ObjectAnimator scaleX = ObjectAnimator.ofFloat(imageView, "scaleX", 0.2f, 1f);
  ObjectAnimator scaleY = ObjectAnimator.ofFloat(imageView, "scaleY", 0.2f, 1f);
  AnimatorSet set = new AnimatorSet();
  set.setDuration(100);
  set.playTogether(alpha, scaleX, scaleY);
  set.setTarget(imageView);
  set.addListener(new Animator.AnimatorListener() {
   @Override
   public void onAnimationStart(Animator animation) {

   }

   @Override
   public void onAnimationEnd(Animator animation) {
    //設(shè)置貝塞爾曲線移動效果
    ValueAnimator va = getBzierAnimator(imageView);//第二部分動畫
    va.start();
   }

   @Override
   public void onAnimationCancel(Animator animation) {

   }

   @Override
   public void onAnimationRepeat(Animator animation) {

   }
  });
  set.start();
 }

 //初始化貝塞爾曲線的4個點
 private void initPointF() {
  mPointF0 = new PointF(mScreenWidth - 60 - 50, mScreenHeight - 60 - 50);//起點是初始化時的點
  mPointF1 = new PointF(mRandom.nextInt(mScreenWidth), mRandom.nextInt((int) mPointF0.y));//第一個控制點必須要在起始點的上方
  mPointF2 = new PointF(mRandom.nextInt(mScreenWidth), mRandom.nextInt((int) mPointF1.y));//第二個控制點必須在第一個點的上方
  mPointF3 = new PointF(mRandom.nextInt(mScreenWidth), -50);//終點在屏幕的最頂部0-圖片的高度
 }


 /**
  * 自定義估值器計算圖片移動的軌跡
  * 計算公式參考貝塞爾曲線3階計算公式
  * 自定義估值器的方法可百度搜索
  * 其中估值器定義返回的結(jié)果為PointF
  */
 public class BezierEvaluator implements TypeEvaluator<PointF> {
  private PointF pointF1, pointF2;

  public BezierEvaluator(PointF p1, PointF p2) {
   this.pointF1 = p1;
   this.pointF2 = p2;
  }

  @Override
  public PointF evaluate(float t, PointF p0, PointF p3) {
   PointF point = new PointF();
   point.x = p0.x * (1 - t) * (1 - t) * (1 - t) //
     + 3 * pointF1.x * t * (1 - t) * (1 - t)//
     + 3 * pointF2.x * t * t * (1 - t)//
     + p3.x * t * t * t;//

   point.y = p0.y * (1 - t) * (1 - t) * (1 - t) //
     + 3 * pointF1.y * t * (1 - t) * (1 - t)//
     + 3 * pointF2.y * t * t * (1 - t)//
     + p3.y * t * t * t;//
   return point;
  }
 }

 private ValueAnimator getValueAnimator(final ImageView imageView) {
  initPointF();
  BezierEvaluator bezierEvaluator = new BezierEvaluator(mPointF1, mPointF2);
  ValueAnimator valueAnimator = ValueAnimator.ofObject(bezierEvaluator, mPointF0, mPointF3);
  valueAnimator.setDuration(3000);
  valueAnimator.setTarget(imageView);
  valueAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
   @Override
   public void onAnimationUpdate(ValueAnimator animation) {
    //改變imageview位置實現(xiàn)移動效果
    PointF point = (PointF) animation.getAnimatedValue();
    imageView.setX(point.x);
    imageView.setY(point.y);
    imageView.setAlpha(1 - animation.getAnimatedFraction());
    //動畫結(jié)束移除imageview
    if (animation.getAnimatedFraction() >= 1) {
     removeView(imageView);
    }
   }
  });
  return valueAnimator;
 }

 /**
  * 貝塞爾動畫
  * */
 private ValueAnimator getBzierAnimator(final ImageView iv) {
  // TODO Auto-generated method stub
  PointF[] PointFs = getPointFs(iv); // 4個點的坐標
  BezierEvaluator evaluator = new BezierEvaluator(PointFs[1], PointFs[2]);
  ValueAnimator valueAnim = ValueAnimator.ofObject(evaluator, PointFs[0], PointFs[3]);
  valueAnim.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {

   @Override
   public void onAnimationUpdate(ValueAnimator animation) {
    // TODO Auto-generated method stub
    PointF p = (PointF) animation.getAnimatedValue();
    iv.setX(p.x);
    iv.setY(p.y);
    iv.setAlpha(1- animation.getAnimatedFraction()); // 透明度
    //動畫結(jié)束移除imageview
    if (animation.getAnimatedFraction() >= 1) {
     removeView(iv);
    }
   }
  });
  valueAnim.setTarget(iv);
  valueAnim.setDuration(3000);
  valueAnim.setInterpolator(interpolators[new Random().nextInt(4)]);
  return valueAnim;
 }

 private PointF[] getPointFs(ImageView iv) {
  // TODO Auto-generated method stub
  PointF[] PointFs = new PointF[4];
  PointFs[0] = new PointF(); // p0
  PointFs[0].x = (mScreenWidth- layoutParams.width)/ 2;
  PointFs[0].y = mScreenHeight - layoutParams.height;

  PointFs[1] = new PointF(); // p1
  PointFs[1].x = new Random().nextInt(mScreenWidth);
  PointFs[1].y = new Random().nextInt(mScreenHeight /2) + mScreenHeight / 2 + layoutParams.height;

  PointFs[2] = new PointF(); // p2
  PointFs[2].x = new Random().nextInt(mScreenWidth);
  PointFs[2].y = new Random().nextInt(mScreenHeight /2);

  PointFs[3] = new PointF(); // p3
  PointFs[3].x = new Random().nextInt(mScreenWidth);
  PointFs[3].y = 0;
  return PointFs;
 }
}

2.givepraise_layout.xml

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
 android:layout_width="match_parent"
 android:layout_height="match_parent"
 android:background="@android:color/darker_gray">
 <com.xinrui.ndkapp.view.GivePraiseView
  android:layout_width="match_parent"
  android:layout_height="match_parent"/>
 <!--<com.xinrui.ndkapp.view.LoveLayout-->
  <!--android:layout_width="match_parent"-->
  <!--android:layout_height="match_parent"/>-->
</RelativeLayout>

3.Activity 部分代碼

import android.app.Activity;
import android.os.Bundle;

public class GivePraiseActivity extends Activity {
 @Override
 protected void onCreate(Bundle savedInstanceState) {
  super.onCreate(savedInstanceState);
  setContentView(R.layout.givepraise_layout);
 }
}

4.估值器的運算

p0坐標:x坐標((布局的寬-心形圖片寬)除以2),y坐標(布局的高 -心形圖片高),這樣獲得的是頂部部水平中心點的坐標。
p1坐標:x坐標(橫坐標中的隨機位置),y坐標(布局一半的高度 加上 0到一半高度范圍內(nèi)的隨機坐標+心形的高度的一半)。這樣取到的橫坐標是在布局寬度之內(nèi)的隨機坐標,縱坐標為整個路徑高度中部以上的隨機坐標。
p2坐標:與p1類似,橫坐標是在布局寬度之內(nèi)的隨機坐標,縱坐標為整個路徑高度中部以下的隨機坐標。
p3坐標:控件底部中心點
知道4個坐標了,那么就可以開始計算路徑

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

相關(guān)文章

最新評論