android实现直播点赞飘心动画效果

android实现直播点赞飘心动画效果,第1张

概述前段时间在写直播的时候,需要观众在看直播的时候点赞的效果,在此参照了腾讯大神写的点赞(飘心动画效果)。下面是效果图:

前段时间在写直播的时候,需要观众在看直播的时候点赞的效果,在此参照了腾讯大神写的点赞(飘心动画效果)。下面是效果图:

1.自定义飘心动画的属性

在attrs.xml 中增加自定义的属性

<!-- 飘心动画自定义的属性 --> <declare-styleable name="HeartLayout">  <attr name="initX" format="dimension"/>  <attr name="initY" format="dimension"/>  <attr name="xRand" format="dimension"/>  <attr name="animLengthRand" format="dimension"/>  <attr name="xPointFactor" format="dimension"/>  <attr name="animLength" format="dimension"/>  <attr name="heart_wIDth" format="dimension"/>  <attr name="heart_height" format="dimension"/>  <attr name="bezIErFactor" format="integer"/>  <attr name="anim_duration" format="integer"/> </declare-styleable>

2.定义飘心默认值

2.1 dimens.xml

<!-- 飘星 --> <dimen name="heart_anim_bezIEr_x_rand">50.0dp</dimen> <dimen name="heart_anim_init_x">50.0dp</dimen> <dimen name="heart_anim_init_y">25.0dp</dimen> <dimen name="heart_anim_length">400.0dp</dimen> <dimen name="heart_anim_length_rand">350.0dp</dimen> <dimen name="heart_anim_x_point_factor">30.0dp</dimen> <dimen name="heart_size_height">27.3dp</dimen> <dimen name="heart_size_wIDth">32.5dp</dimen>

2.2 integers.xml

<?xml version="1.0" enCoding="utf-8"?><resources> <integer name="heart_anim_bezIEr_factor">6</integer> <integer name="anim_duration">3000</integer></resources>

3.定义飘心动画控制器

3.1 AbstractPathAnimator.java

public abstract class AbstractPathAnimator { private final Random mRandom; protected final Config mConfig; public AbstractPathAnimator(Config config) {  mConfig = config;  mRandom = new Random(); } public float randomrotation() {  return mRandom.nextfloat() * 28.6F - 14.3F; } public Path createPath(AtomicInteger counter,VIEw vIEw,int factor) {  Random r = mRandom;  int x = r.nextInt(mConfig.xRand);  int x2 = r.nextInt(mConfig.xRand);  int y = vIEw.getHeight() - mConfig.initY;  int y2 = counter.intValue() * 15 + mConfig.animLength * factor + r.nextInt(mConfig.animLengthRand);  factor = y2 / mConfig.bezIErFactor;  x = mConfig.xPointFactor + x;  x2 = mConfig.xPointFactor + x2;  int y3 = y - y2;  y2 = y - y2 / 2;  Path p = new Path();  p.moveto(mConfig.initX,y);  p.cubicTo(mConfig.initX,y - factor,x,y2 + factor,y2);  p.moveto(x,y2);  p.cubicTo(x,y2 - factor,x2,y3 + factor,y3);  return p; } public abstract voID start(VIEw child,VIEwGroup parent); public static class Config {  public int initX;  public int initY;  public int xRand;  public int animLengthRand;  public int bezIErFactor;  public int xPointFactor;  public int animLength;  public int heartWIDth;  public int heartHeight;  public int animDuration;  static public Config fromTypeArray(TypedArray typedArray,float x,float y,int pointx,int heartWIDth,int heartHeight) {   Config config = new Config();   Resources res = typedArray.getResources();   config.initX = (int) typedArray.getDimension(R.styleable.HeartLayout_initX,x);   config.initY = (int) typedArray.getDimension(R.styleable.HeartLayout_initY,y);   config.xRand = (int) typedArray.getDimension(R.styleable.HeartLayout_xRand,res.getDimensionPixelOffset(R.dimen.heart_anim_bezIEr_x_rand));   config.animLength = (int) typedArray.getDimension(R.styleable.HeartLayout_animLength,res.getDimensionPixelOffset(R.dimen.heart_anim_length));//动画长度   config.animLengthRand = (int) typedArray.getDimension(R.styleable.HeartLayout_animLengthRand,res.getDimensionPixelOffset(R.dimen.heart_anim_length_rand));   config.bezIErFactor = typedArray.getInteger(R.styleable.HeartLayout_bezIErFactor,res.getInteger(R.integer.heart_anim_bezIEr_factor));   config.xPointFactor = pointx;//   config.heartWIDth = (int) typedArray.getDimension(R.styleable.HeartLayout_heart_wIDth,//     res.getDimensionPixelOffset(R.dimen.heart_size_wIDth));//动画图片宽度//   config.heartHeight = (int) typedArray.getDimension(R.styleable.HeartLayout_heart_height,//     res.getDimensionPixelOffset(R.dimen.heart_size_height));//动画图片高度   config.heartWIDth = heartWIDth;   config.heartHeight = heartHeight;   config.animDuration = typedArray.getInteger(R.styleable.HeartLayout_anim_duration,res.getInteger(R.integer.anim_duration));//持续期   return config;  } }}

3.2 PathAnimator.java

/** * 飘心路径动画器 */public class PathAnimator extends AbstractPathAnimator { private final AtomicInteger mCounter = new AtomicInteger(0); private Handler mHandler; public PathAnimator(Config config) {  super(config);  mHandler = new Handler(Looper.getMainLooper()); } @OverrIDe public voID start(final VIEw child,final VIEwGroup parent) {  parent.addVIEw(child,new VIEwGroup.LayoutParams(mConfig.heartWIDth,mConfig.heartHeight));  floatAnimation anim = new floatAnimation(createPath(mCounter,parent,2),randomrotation(),child);  anim.setDuration(mConfig.animDuration);  anim.setInterpolator(new linearInterpolator());  anim.setAnimationListener(new Animation.AnimationListener() {   @OverrIDe   public voID onAnimationEnd(Animation animation) {    mHandler.post(new Runnable() {     @OverrIDe     public voID run() {      parent.removeVIEw(child);     }    });    mCounter.decrementAndGet();   }   @OverrIDe   public voID onAnimationRepeat(Animation animation) {   }   @OverrIDe   public voID onAnimationStart(Animation animation) {    mCounter.incrementAndGet();   }  });  anim.setInterpolator(new linearInterpolator());  child.startAnimation(anim); } static class floatAnimation extends Animation {  private PathMeasure mPm;  private VIEw mVIEw;  private float mdistance;  private float mRotation;  public floatAnimation(Path path,float rotation,VIEw parent,VIEw child) {   mPm = new PathMeasure(path,false);   mdistance = mPm.getLength();   mVIEw = child;   mRotation = rotation;   parent.setLayerType(VIEw.LAYER_TYPE_HARDWARE,null);  }  @OverrIDe  protected voID applytransformation(float factor,transformation transformation) {   Matrix matrix = transformation.getMatrix();   mPm.getMatrix(mdistance * factor,matrix,PathMeasure.position_MATRIX_FLAG);   mVIEw.setRotation(mRotation * factor);   float scale = 1F;   if (3000.0F * factor < 200.0F) {    scale = scale(factor,0.0D,0.06666667014360428D,0.20000000298023224D,1.100000023841858D);   } else if (3000.0F * factor < 300.0F) {    scale = scale(factor,0.10000000149011612D,1.100000023841858D,1.0D);   }   mVIEw.setScaleX(scale);   mVIEw.setScaleY(scale);   transformation.setAlpha(1.0F - factor);  } } private static float scale(double a,double b,double c,double d,double e) {  return (float) ((a - b) / (c - b) * (e - d) + d); }}

4.定义飘心界面

4.1 HeartVIEw.java

/** * 飘心动画的界面 */public class HeartVIEw extends ImageVIEw{ //绘制的时候抗锯齿 private static final Paint sPaint = new Paint(Paint.ANTI_AliAS_FLAG | Paint.FILTER_BITMAP_FLAG); private static final Canvas sCanvas = new Canvas(); private int mHeartResID = R.drawable.heart0; private int mHeartborderResID = R.drawable.heart1; private static Bitmap sHeart; private static Bitmap sHeartborder; public HeartVIEw(Context context) {  super(context); } public HeartVIEw(Context context,AttributeSet attrs) {  super(context,attrs); } public HeartVIEw(Context context,AttributeSet attrs,int defStyleAttr) {  super(context,attrs,defStyleAttr); } public voID setDrawable(int resourceID){  Bitmap heart = BitmapFactory.decodeResource(getResources(),resourceID);  // Sets a drawable as the content of this ImageVIEw.  setimageDrawable(new BitmapDrawable(getResources(),heart)); } public voID setcolor(int color) {  Bitmap heart = createHeart(color);  setimageDrawable(new BitmapDrawable(getResources(),heart)); } public voID setcolorAndDrawables(int color,int heartResID,int heartborderResID) {  if (heartResID != mHeartResID) {   sHeart = null;  }  if (heartborderResID != mHeartborderResID) {   sHeartborder = null;  }  mHeartResID = heartResID;  mHeartborderResID = heartborderResID;  setcolor(color); } public Bitmap createHeart(int color) {  if (sHeart == null) {   sHeart = BitmapFactory.decodeResource(getResources(),mHeartResID);  }  if (sHeartborder == null) {   sHeartborder = BitmapFactory.decodeResource(getResources(),mHeartborderResID);  }  Bitmap heart = sHeart;  Bitmap heartborder = sHeartborder;  Bitmap bm = createBitmapSafely(heartborder.getWIDth(),heartborder.getHeight());  if (bm == null) {   return null;  }  Canvas canvas = sCanvas;  canvas.setBitmap(bm);  Paint p = sPaint;  canvas.drawBitmap(heartborder,p);  p.setcolorFilter(new PorterDuffcolorFilter(color,PorterDuff.Mode.SRC_Atop));  float dx = (heartborder.getWIDth() - heart.getWIDth()) / 2f;  float dy = (heartborder.getHeight() - heart.getHeight()) / 2f;  canvas.drawBitmap(heart,dx,dy,p);  p.setcolorFilter(null);  canvas.setBitmap(null);  return bm; } private static Bitmap createBitmapSafely(int wIDth,int height) {  try {   return Bitmap.createBitmap(wIDth,height,Bitmap.Config.ARGB_8888);  } catch (OutOfMemoryError error) {   error.printstacktrace();  }  return null; }}

4.2 飘心动画路径布局

HeartLayout.java

/** * 飘心动画路径 */public class HeartLayout extends relativeLayout implements VIEw.OnClickListener { private AbstractPathAnimator mAnimator; private AttributeSet attrs = null; private int defStyleAttr = 0; private OnHearLayoutListener onHearLayoutListener; private static HeartHandler heartHandler; private static HeartThread heartThread; public voID setonHearLayoutListener(OnHearLayoutListener onHearLayoutListener) {  this.onHearLayoutListener = onHearLayoutListener; } public interface OnHearLayoutListener {  boolean onAddFavor(); } public HeartLayout(Context context) {  super(context);  findVIEwByID(context); } public HeartLayout(Context context,attrs);  this.attrs = attrs;  findVIEwByID(context); } public HeartLayout(Context context,defStyleAttr);  this.attrs = attrs;  this.defStyleAttr = defStyleAttr;  findVIEwByID(context); } private Bitmap bitmap; private voID findVIEwByID(Context context) {  LayoutInflater.from(context).inflate(R.layout.ly_periscope,this);  bitmap = BitmapFactory.decodeResource(getResources(),R.drawable.icon_like);  dHeight = bitmap.getWIDth()/2;  DWIDth = bitmap.getHeight()/2;  textHight = sp2px(getContext(),20) + dHeight / 2;  pointx = DWIDth;//随机上浮方向的x坐标  bitmap.recycle(); } private int mHeight; private int mWIDth; private int textHight; private int dHeight; private int DWIDth; private int initX; private int pointx; public static int sp2px(Context context,float spValue) {  final float FontScale = context.getResources().getdisplayMetrics().scaledDensity;  return (int) (spValue * FontScale + 0.5f); } public class HeartHandler extends Handler {  public final static int MSG_SHOW = 1;  WeakReference<HeartLayout> wf;  public HeartHandler(HeartLayout layout) {   wf = new WeakReference<HeartLayout>(layout);  }  @OverrIDe  public voID handleMessage(Message msg) {   super.handleMessage(msg);   HeartLayout layout = wf.get();   if (layout == null) return;   switch (msg.what) {    case MSG_SHOW:     addFavor();     break;   }  } } public class HeartThread implements Runnable {  private long time = 0;  private int allSize = 0;  public voID addTask(long time,int size) {   this.time = time;   allSize += size;  }  public voID clean() {   allSize = 0;  }  @OverrIDe  public voID run() {   if (heartHandler == null) return;   if (allSize > 0) {    heartHandler.sendEmptyMessage(HeartHandler.MSG_SHOW);    allSize--;   }   postDelayed(this,time);  } } private voID init(AttributeSet attrs,int defStyleAttr) {  final TypedArray a = getContext().obtainStyledAttributes(    attrs,R.styleable.HeartLayout,defStyleAttr,0);  if (pointx <= initX && pointx >= 0) {   pointx -= 10;  } else if (pointx >= -initX && pointx <= 0) {   pointx += 10;  } else pointx = initX;  mAnimator = new PathAnimator(AbstractPathAnimator.Config.fromTypeArray(a,initX,textHight,pointx,DWIDth,dHeight));  a.recycle(); } @OverrIDe protected voID onMeasure(int wIDthMeasureSpec,int heightmeasureSpec) {  super.onMeasure(wIDthMeasureSpec,heightmeasureSpec);  //获取本身的宽高 这里要注意,测量之后才有宽高  mWIDth = getMeasureDWIDth();  mHeight = getMeasuredHeight();  initX = mWIDth / 2 - DWIDth / 2; } public AbstractPathAnimator getAnimator() {  return mAnimator; } public voID setAnimator(AbstractPathAnimator animator) {  clearanimation();  mAnimator = animator; } public voID clearanimation() {  for (int i = 0; i < getChildCount(); i++) {   getChildAt(i).clearanimation();  }  removeAllVIEws(); } private static int[] drawableIDs = new int[]{R.drawable.heart0,R.drawable.heart1,R.drawable.heart2,R.drawable.heart3,R.drawable.heart4,R.drawable.heart5,R.drawable.heart6,R.drawable.heart7,R.drawable.heart8,}; private Random random = new Random(); public voID addFavor() {  HeartVIEw heartVIEw = new HeartVIEw(getContext());  heartVIEw.setDrawable(drawableIDs[random.nextInt(8)]);  init(attrs,defStyleAttr);  mAnimator.start(heartVIEw,this); } private long NowTime,lastTime; final static int[] sizetable = {9,99,999,9999,99999,999999,9999999,99999999,999999999,Integer.MAX_VALUE}; public static int sizeOfInt(int x) {  for (int i = 0; ; i++)   if (x <= sizetable[i])    return i + 1; } public voID addFavor(int size) {  switch (sizeOfInt(size)) {   case 1:    size = size % 10;    break;   default:    size = size % 100;  }  if (size == 0) return;  NowTime = System.currentTimeMillis();  long time = NowTime - lastTime;  if (lastTime == 0)   time = 2 * 1000;//第一次分为2秒显示完  time = time / (size + 15);  if (heartThread == null) {   heartThread = new HeartThread();  }  if (heartHandler == null) {   heartHandler = new HeartHandler(this);   heartHandler.post(heartThread);  }  heartThread.addTask(time,size);  lastTime = NowTime; } public voID addHeart(int color) {  HeartVIEw heartVIEw = new HeartVIEw(getContext());  heartVIEw.setcolor(color);  init(attrs,this); } public voID addHeart(int color,int heartborderResID) {  HeartVIEw heartVIEw = new HeartVIEw(getContext());  heartVIEw.setcolorAndDrawables(color,heartResID,heartborderResID);  init(attrs,this); } @OverrIDe public voID onClick(VIEw v) {  int i = v.getID();  if (i == R.ID.img) {   if (onHearLayoutListener != null) {    boolean isAdd = onHearLayoutListener.onAddFavor();    if (isAdd) addFavor();   }  } } public voID clean() {  if (heartThread != null) {   heartThread.clean();  } } public voID release() {  if (heartHandler != null) {   heartHandler.removeCallbacks(heartThread);   heartThread = null;   heartHandler = null;  } }}

5.飘心动画的使用

5.1 activity_heart_animal.xml

<?xml version="1.0" enCoding="utf-8"?><relativeLayout xmlns:androID="http://schemas.androID.com/apk/res/androID"    androID:orIEntation="vertical"    androID:layout_wIDth="match_parent"    androID:layout_height="match_parent"    androID:background="@color/grey"    androID:Alpha="0.5"> <TextVIEw   androID:ID="@+ID/member_send_good"   androID:layout_wIDth="40dp"   androID:layout_height="40dp"   androID:layout_gravity="center"   androID:layout_alignParentBottom="true"   androID:layout_alignParentRight="true"   androID:layout_marginRight="30dp"   androID:layout_marginBottom="10dp"   androID:background="@drawable/live_like_icon"   /> <!-- 飘心的路径 --> <com.myapplication2.app.newsdemo.vIEw.heartvIEw.HeartLayout   androID:ID="@+ID/heart_layout"   androID:layout_wIDth="100dp"   androID:layout_height="wrap_content"   androID:layout_alignParentRight="true"   androID:layout_alignParentBottom="true"/></relativeLayout>

5.2 activity 中的使用

heartLayout = (HeartLayout)findVIEwByID(R.ID.heart_layout);  findVIEwByID(R.ID.member_send_good).setonClickListener(new VIEw.OnClickListener() {   @OverrIDe   public voID onClick(VIEw v) {    heartLayout.addFavor();   }  });

heartLayout.addFavor(); 就是触发飘心动画效果的关键代码

6.参看资料

https://github.com/zhaoyang21cn/Android_Suixinbo

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持编程小技巧。

您可能感兴趣的文章:Android控件实现直播App特效之点赞飘心动画Android仿直播特效之点赞飘心效果Android贝塞尔曲线实现直播点赞效果Android高级UI特效仿直播点赞动画效果 总结

以上是内存溢出为你收集整理的android实现直播点赞飘心动画效果全部内容,希望文章能够帮你解决android实现直播点赞飘心动画效果所遇到的程序开发问题。

如果觉得内存溢出网站内容还不错,欢迎将内存溢出网站推荐给程序员好友。

欢迎分享,转载请注明来源:内存溢出

原文地址: http://outofmemory.cn/web/1142914.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2022-05-31
下一篇 2022-05-31

发表评论

登录后才能评论

评论列表(0条)

保存