仿某直播平台的点赞效果
程序员文章站
2024-03-22 21:48:04
...
现在的直播平台已经是多的不得了了,而给主播点赞的效果,也是各不相同,今天,我们来自定义一个点赞的效果!
先上效果:
当点击点赞按钮的时候,就会有不同颜色的心型从底部冒出,并按照不规则的路线运动,在运动过程中,伴随着各种动画!
好了,话不多说,直接上代码:
/**
* 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;
}
}
按照以往的风格,注释都加在代码中了,如果大家还发现了什么问题,请回复我,大家一起讨论下!
最后,再来看一次效果: