仿某直播平臺的點贊效果
阿新 • • 發佈:2019-01-11
現在的直播平臺已經是多的不得了了,而給主播點讚的效果,也是各不相同,今天,我們來自定義一個點讚的效果!
先上效果:
當點選點贊按鈕的時候,就會有不同顏色的心型從底部冒出,並按照不規則的路線運動,在運動過程中,伴隨著各種動畫!
好了,話不多說,直接上程式碼:
/**
* Created by DELL on 2017/9/16.
* Description : 花束點贊效果
*/
public class PraiseView extends RelativeLayout {
private int[] drawables;
private Context mContext;
//圖片的寬高
private int mDrawableHeight;
private int mDrawableWidth;
//隨機數
private Random mRandom;
public PraiseView(Context context) {
this(context,null);
}
public PraiseView(Context context, AttributeSet attrs) {
this(context, attrs,0);
}
public PraiseView (Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
this.mContext = context;
//建立隨機數 在後面的貝塞爾取點鐘會用到
mRandom = new Random();
//初始化心形圖片
drawables = new int[]{R.drawable.pl_blue,R.drawable.pl_red,R.drawable.pl_yellow};
//獲取心形圖片的寬高
Drawable drawable = ContextCompat.getDrawable(context,drawables[0]);
mDrawableHeight = drawable.getIntrinsicHeight();
mDrawableWidth = drawable.getIntrinsicWidth();
}
//在螢幕底部新增心形圖片
public void addDrawables(){
final ImageView imageView = new ImageView(mContext);
imageView.setImageResource(drawables[mRandom.nextInt(drawables.length-1)]);
RelativeLayout.LayoutParams params = new RelativeLayout.LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT, LinearLayout.LayoutParams.WRAP_CONTENT);
params.addRule(ALIGN_PARENT_BOTTOM);
params.addRule(CENTER_HORIZONTAL);
imageView.setLayoutParams(params);
addView(imageView);
//建立並開啟動畫效果
AnimatorSet animatorSet = getAnimator(imageView);
animatorSet.addListener(new AnimatorListenerAdapter() {
@Override
public void onAnimationEnd(Animator animation) {
super.onAnimationEnd(animation);
//在動畫執行結束之後,移除該view
removeView(imageView);
}
});
animatorSet.start();
}
//建立動畫
/**
* 剛開始做縮放和漸變動畫 結束後開始做移動動畫
* @param imageView
* @return
*/
private AnimatorSet getAnimator(ImageView imageView){
//縮放動畫
ObjectAnimator scaleXAnimator = ObjectAnimator.ofFloat(imageView,"scaleX",0.3f,1f);
ObjectAnimator scaleYAnimator = ObjectAnimator.ofFloat(imageView,"scaleY",0.3f,1f);
//漸變動畫
ObjectAnimator alphaAnimator = ObjectAnimator.ofFloat(imageView,"alpha",0.3f,1f);
AnimatorSet set = new AnimatorSet();
set.playTogether(scaleXAnimator,scaleYAnimator,alphaAnimator);
set.setDuration(300);
//建立平移動畫並新增到set執行完成之後執行
AnimatorSet wholeAnimator = new AnimatorSet();
//按照順序執行
wholeAnimator.playSequentially(set,getBeizerAnimator(imageView));
return wholeAnimator;
}
private ValueAnimator getBeizerAnimator(final ImageView imageView){
//首先先確定需要用到的四個點
//點0是在圖片開始的中心點
final PointF point0 = new PointF(getWidth()/2 - mDrawableWidth/2,getHeight() - mDrawableHeight);
//點1 點2是貝塞爾曲線的控制點 需要控制的是,點2的高度要大於點1的高度
PointF point1 = getPoint(1);
PointF point2 = getPoint(2);
PointF point3 = new PointF(mRandom.nextInt(getWidth()/2) - mDrawableWidth/2,0);
BeizerEvalator beizerEvalator = new BeizerEvalator(point1,point2);
ValueAnimator beizerAnimator = ObjectAnimator.ofObject(beizerEvalator,point0,point3);
beizerAnimator.setInterpolator(new AccelerateDecelerateInterpolator());
beizerAnimator.setDuration(4000);
beizerAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
@Override
public void onAnimationUpdate(ValueAnimator animation) {
//在執行過程中會呼叫該方法
PointF pointF = (PointF) animation.getAnimatedValue();
imageView.setX(pointF.x);
imageView.setY(pointF.y);
//設定移動過程中的漸變
//首先獲取當前的fraction
float fraction = animation.getAnimatedFraction();
imageView.setAlpha(1-fraction);
}
});
return beizerAnimator;
}
private PointF getPoint(int i){
return new PointF(mRandom.nextInt(getWidth())- mDrawableWidth,mRandom.nextInt(getHeight()/2) + (i-1)*getHeight()/2);
}
}
然後,我們需要一個估值器,來確定在某一時刻,沿著貝塞爾曲線的路徑的點(這邊,其實只要套公式就可以了)
/**
* Created by DELL on 2017/9/16.
* Description : 貝塞爾運動軌跡估值器
*/
public class BeizerEvalator implements TypeEvaluator<PointF> {
private PointF point1,point2;
public BeizerEvalator(PointF point1,PointF point2){
this.point1 = point1;
this.point2 = point2;
}
//直接套用貝塞爾三階公式
@Override
public PointF evaluate(float fraction, PointF point0, PointF point3) {
PointF pointF = new PointF();
pointF.x = point0.x*(1-fraction)*(1-fraction)*(1-fraction)
+ 3*point1.x*fraction*(1-fraction)*(1-fraction)
+ 3*point2.x*fraction*fraction*(1-fraction)
+ point3.x*fraction*fraction*fraction;
pointF.y = point0.y*(1-fraction)*(1-fraction)*(1-fraction)
+ 3*point1.y*fraction*(1-fraction)*(1-fraction)
+ 3*point2.y*fraction*fraction*(1-fraction)
+ point3.y*fraction*fraction*fraction;
return pointF;
}
}
按照以往的風格,註釋都加在程式碼中了,如果大家還發現了什麼問題,請回復我,大家一起討論下!
最後,再來看一次效果: