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

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

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, x, y2);
  p.moveTo(x, y2);
  p.cubicTo(x, y2 - factor, x2, y3 + factor, x2, 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(), parent, 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.06666667014360428D, 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, 0, 0, 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, AttributeSet attrs) {
  super(context, attrs);
  this.attrs = attrs;
  findViewById(context);
 }

 public HeartLayout(Context context, AttributeSet attrs, int defStyleAttr) {
  super(context, attrs, 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, defStyleAttr);
  mAnimator.start(heartView, this);
 }

 public void addHeart(int color, int heartResId, int heartBorderResId) {
  HeartView heartView = new HeartView(getContext());
  heartView.setColorAndDrawables(color, heartResId, heartBorderResId);
  init(attrs, defStyleAttr);
  mAnimator.start(heartView, 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仿斗鱼直播的弹幕效果
  • Android自定义View模仿虎扑直播界面的打赏按钮功能
  • Android高级UI特效仿直播点赞动画效果
  • Android仿直播特效之点赞飘心效果
  • Android控件实现直播App特效之点赞飘心动画
  • Android贝塞尔曲线实现直播点赞效果
  • Android实现直播聊天区域中顶部的渐变效果
(0)

相关推荐

  • Android仿斗鱼直播的弹幕效果

    记得之前有位朋友在我的公众号里问过我,像直播的那种弹幕功能该如何实现?如今直播行业确实是非常火爆啊,大大小小的公司都要涉足一下直播的领域,用斗鱼的话来讲,现在就是千播之战.而弹幕则无疑是直播功能当中最为重要的一个功能之一,那么今天,我就带着大家一起来实现一个简单的Android端弹幕效果. 分析 首先我们来看一下斗鱼上的弹幕效果,如下图所示: 这是一个Dota2游戏直播的界面,我们可以看到,在游戏界面的上方有很多的弹幕,看直播的观众们就是在这里进行讨论的. 那么这样的一个界面该如何实现呢?其实并

  • Android实现炫酷的网络直播弹幕功能

    现在网络直播越来越火,网络主播也逐渐成为一种新兴职业,对于网络直播,弹幕功能是必须要有的,如下图: 首先来分析一下,这个弹幕功能是怎么实现的,首先在最下面肯定是一个游戏界面View,然后游戏界面上有弹幕View,弹幕的View必须要做成完全透明的,这样即使覆盖在游戏界面的上方也不会影响到游戏的正常观看,只有当有人发弹幕消息时,再将消息绘制到弹幕的View上面就可以了,下方肯定还有有操作界面View,可以让用户来发弹幕和送礼物的功能,原理示意图如下所示: 参照原理图,下面一步一步来实现这个功能.

  • Android高级UI特效仿直播点赞动画效果

    本文给大家分享高级UI特效仿直播点赞效果-一个优美炫酷的点赞动画,具体实现代码大家参考本文. 效果图如下: 攻克难点: 心形图片的路径等走向 心形图片的控制范围 部分代码如下: 通过AbstractPathAnimator定义飘心动画控制器 @Override public void start(final View child, final ViewGroup parent) { parent.addView(child, new ViewGroup.LayoutParams(mConfig.

  • Android仿直播特效之点赞飘心效果

    本文实例为大家分享了Android实现点赞飘心效果的具体代码,供大家参考,具体内容如下 一.概述 老规矩先上图 好了,基本就是这个样子,录完的视频用格式工厂转换完就这个样子了,将就看吧 二.定义我们自己的Layout /** * @author 刘洋巴金 * @date 2017-4-27 * * 定义我们自己的布局 * */ public class LoveLayout extends RelativeLayout{ private Context context; private Layo

  • Android 实现仿网络直播弹幕功能详解及实例

    Android 网络直播弹幕                最近看好多网络电视,播放器及直播都有弹幕功能,自己周末捣鼓下并实现,以下是网上的资料,大家可以看下. 现在网络直播越来越火,网络主播也逐渐成为一种新兴职业,对于网络直播,弹幕功能是必须要有的,如下图: 首先来分析一下,这个弹幕功能是怎么实现的,首先在最下面肯定是一个游戏界面View,然后游戏界面上有弹幕View,弹幕的View必须要做成完全透明的,这样即使覆盖在游戏界面的上方也不会影响到游戏的正常观看,只有当有人发弹幕消息时,再将消息绘

  • Android贝塞尔曲线实现直播点赞效果

    本文实例为大家分享了Android实现直播点赞效果的具体代码,供大家参考,具体内容如下 效果展示 原理分析 点赞效果最主要的难点和原理在于贝塞尔曲线动画的生成,我们通过图片主要讲解贝塞尔曲线动画 1.需要找到贝塞尔曲线的四个点 2.通过三级贝塞尔曲线的公式计算,获取贝塞尔曲线的轨迹路径点 3.通过设置点赞图片X,Y坐标,从而形成点赞的效果 实现步骤 1.初始化变量 //1.继承RelativeLayout public class ChristmasView extends RelativeLa

  • Android实现直播聊天区域中顶部的渐变效果

    背景 在4月份开发直播时,有一个需求,需要实现一个RecylerView顶部渐变的效果 实际效果 解决思路 图层重叠处理(本质是alpha叠加出来的效果) 实现流程 保存一个图层,然后画渐变,最后再和原来的图层进行合并,达到这个效果. 涉及知识(不知道的请google): *      主要通过RecyclerView 的 ItemDecoration类进行解决. *      Paint.Canvas.Shader.Xfermode(图层融合) *      Gradient(渐变) 详细过程

  • Android控件实现直播App特效之点赞飘心动画

    现在市面上直播类的应用可以说是一抓一大把,随随便便就以什么主题来开发个直播App,说白了就想在这领域分杯羹.在使用这些应用过程中其实不难发现,在所有的直播界面,少不了的就是各种打赏.各种点赞.今天自己就针对点赞功能敲了一下,代码不多,主要是涉及到动画运动轨迹运算,这里需借助 贝塞尔曲线 相关知识,我使用三阶贝塞尔曲线来实现轨迹动画. 运行效果 一.具体实现流程 仔细分析整个点赞过程可以发现,首先是"爱心"的出现动画,然后是"爱心"以类似气泡的形式向上运动. &quo

  • Android自定义View模仿虎扑直播界面的打赏按钮功能

    前言 作为一个资深篮球爱好者,我经常会用虎扑app看比赛直播,后来注意到文字直播界面右下角加了两个按钮,可以在直播过程中送虎扑币,为自己支持的球队加油. 具体的效果如下图所示: 我个人觉得挺好玩的,所以决定自己实现下这个按钮,废话不多说,先看实现的效果吧: 这个效果看起来和popupwindow差不多,但我是采用自定义view的方式来实现,下面说说过程. 实现过程 首先从虎扑的效果可以看到,它这两个按钮时浮在整个界面之上的,所以它需要和FrameLayout结合使用,因此我让它的宽度跟随屏幕大小

  • Android直播app送礼物连击动画效果(实例代码)

    最近在做公司的直播项目,需要实现一个观看端连击送礼物的控件: 直接上代码: /** * @author yangyinglong on 2017/7/11 16:52. * @Description: todo(这里用一句话描述这个类的作用) * @Copyright Copyright (c) 2017 Tuandai Inc. All Rights Reserved. */ public class CustomGiftView extends LinearLayout { private

随机推荐