这里写链接内容仿映客送小礼物的特效,顺便复习一下属性动画,话不多说先看效果图。

需求分析

可以看到整个动画有几部分组成,那我们就把每个部分拆分出来各个击破。

1.要显示那些内容以及内容间的位置关系?

可以看到我们要显示用户头像,昵称,礼物图标以及数量。所以这里我选择用FrameLayout来作为根布局。

2.需要哪些动画以及动画的执行顺序?

a.首先是整体从左到右飞入并有一个回弹(translationX + OvershootInterpolator)

b.然后是礼物从左到右飞入而且是一个带减速效果的(translationX + DecelerateInterpolator)

c.礼物数量依次累加同时伴随着缩放(scale+repeat)

d.后面的粒子效果(帧动画)

e.整体向上平移并且逐渐消失(translationY + alpha)

3.送礼的区域有两块(A,B),如何分配?

因为用户送礼的数量不固定,所以动画持续的时间也不一定。但是我们希望这两块区域能得到充分的使用,即我们需要一个队列存放这些礼物实例,A和B谁空闲,就分配给谁处理。

4.以上所有内容是否使用原生的空间就能实现?

正如上面的分析,我们有时操作整体,有时操作局部。这时我们最好能自定义一个布局继承FrameLayout,其实也就是封装一层,这样我们就可以很好的控制整个布局。除此之外,还有我们注意到礼物数量是带描边的,貌似需要我们自定义实现了。

功能实现

需求分析完了,接下来我们说说功能的实现。

首先来打我们的整体布局。

xmlns:app="http://schemas.android.com/apk/res-auto"

android:layout_width="match_parent"

android:layout_height="wrap_content">

android:id="@+id/animation_person_rl"

android:layout_width="wrap_content"

android:layout_height="39dp"

android:layout_gravity="left"

android:layout_marginTop="22dp"

android:background="@drawable/bg_giftlayout">

android:id="@+id/gift_userheader_iv"

android:layout_width="39dp"

android:layout_height="39dp"

android:layout_margin="3dp"

android:layout_alignParentLeft="true"

android:layout_centerVertical="true"

android:src="@mipmap/ember" />

android:id="@+id/gift_usernickname_tv"

android:layout_width="wrap_content"

android:layout_height="wrap_content"

android:layout_marginLeft="6dp"

android:layout_marginTop="4dp"

android:layout_toRightOf="@id/gift_userheader_iv"

android:text="库日天"

android:textColor="#ffffff"

android:textSize="12sp" />

android:id="@+id/gift_usersign_tv"

android:layout_width="wrap_content"

android:layout_height="wrap_content"

android:layout_alignLeft="@id/gift_usernickname_tv"

android:layout_below="@id/gift_usernickname_tv"

android:layout_marginTop="4dp"

android:ellipsize="end"

android:text="送一个超级无敌"

android:textColor="#ffea79"

android:textSize="11sp" />

android:id="@+id/animation_gift"

android:layout_width="wrap_content"

android:layout_height="wrap_content"

android:layout_toRightOf="@id/gift_usersign_tv"

android:background="@mipmap/diamond2x" />

android:id="@+id/animation_light"

android:layout_width="wrap_content"

android:layout_height="wrap_content"

android:layout_marginLeft="120dp"

android:src="@drawable/light_star_anim" />

android:id="@+id/animation_num"

android:layout_width="wrap_content"

android:layout_height="wrap_content"

android:layout_marginLeft="185dp"

android:layout_marginTop="12dp"

android:text="x 1"

android:textColor="#0076ff"

android:textSize="24sp"

app:innnerColor="#ffffff"

app:outerColor="#0076ff" />

这里比较简单不多说了,重点看下StrokeTextView,带描边的textview,其实就是重写了ondraw方法先绘制外层,在绘制内层。

@Override

protected void onDraw(Canvas canvas) {

if (m_bDrawSideLine) {

// 描外层

setTextColorUseReflection(mOuterColor);

m_TextPaint.setStrokeWidth(5);

m_TextPaint.setStyle(Paint.Style.FILL_AND_STROKE);

super.onDraw(canvas);

// 描内层,恢复原先的画笔

setTextColorUseReflection(mInnerColor);

m_TextPaint.setStrokeWidth(0);

m_TextPaint.setStyle(Paint.Style.FILL_AND_STROKE);

}

super.onDraw(canvas);

}

/**

* 使用反射的方法进行字体颜色的设置

* @param color

*/

private void setTextColorUseReflection(int color) {

Field textColorField;

try {

textColorField = TextView.class.getDeclaredField("mCurTextColor");

textColorField.setAccessible(true);

textColorField.set(this, color);

textColorField.setAccessible(false);

} catch (NoSuchFieldException e) {

e.printStackTrace();

} catch (IllegalArgumentException e) {

e.printStackTrace();

} catch (IllegalAccessException e) {

e.printStackTrace();

}

m_TextPaint.setColor(color);

}

定义礼物的实体类

public class GiftSendModel {

private int giftCount;

private String userAvatarRes;

private String nickname;

private String sig;

private int giftRes;

private String gift_id;

private int star;

public GiftSendModel(int giftCount) {

this.giftCount = giftCount;

}

public int getGiftCount() {

return giftCount;

}

public void setGiftCount(int giftCount) {

this.giftCount = giftCount;

}

......

封装整体布局

public class GiftFrameLayout extends FrameLayout {

private LayoutInflater mInflater;

RelativeLayout anim_rl;

ImageView anim_gift, anim_light, anim_header;

TextView anim_nickname, anim_sign;

StrokeTextView anim_num;

/**

* 礼物数量的起始值

*/

int starNum = 1;

int repeatCount = 0;

private boolean isShowing = false;

public GiftFrameLayout(Context context) {

this(context, null);

}

public GiftFrameLayout(Context context, AttributeSet attrs) {

super(context, attrs);

mInflater = LayoutInflater.from(context);

initView();

}

private void initView() {

View view = mInflater.inflate(R.layout.animation, this, false);

anim_rl = (RelativeLayout) view.findViewById(R.id.animation_person_rl);

anim_gift = (ImageView) view.findViewById(R.id.animation_gift);

anim_light = (ImageView) view.findViewById(R.id.animation_light);

anim_num = (StrokeTextView) view.findViewById(R.id.animation_num);

anim_header = (ImageView) view.findViewById(R.id.gift_userheader_iv);

anim_nickname = (TextView) view.findViewById(R.id.gift_usernickname_tv);

anim_sign = (TextView) view.findViewById(R.id.gift_usersign_tv);

this.addView(view);

}

public void hideView() {

anim_gift.setVisibility(INVISIBLE);

anim_light.setVisibility(INVISIBLE);

anim_num.setVisibility(INVISIBLE);

}

public void setModel(GiftSendModel model){

if (0!=model.getGiftCount()) {

this.repeatCount = model.getGiftCount();

}

if (!TextUtils.isEmpty(model.getNickname())) {

anim_nickname.setText(model.getNickname());

}

if (!TextUtils.isEmpty(model.getSig())) {

anim_sign.setText(model.getSig());

}

}

public boolean isShowing(){

return isShowing;

}

public AnimatorSet startAnimation( final int repeatCount) {

hideView();

//布局飞入

ObjectAnimator flyFromLtoR = GiftAnimationUtil.createFlyFromLtoR(anim_rl, -getWidth(), 0, 400,new OvershootInterpolator());

flyFromLtoR.addListener(new AnimatorListenerAdapter() {

@Override

public void onAnimationStart(Animator animation) {

super.onAnimationStart(animation);

GiftFrameLayout.this.setVisibility(View.VISIBLE);

GiftFrameLayout.this.setAlpha(1f);

isShowing = true;

anim_num.setText("x " + 1);

Log.i("TAG", "flyFromLtoR A start");

}

});

//礼物飞入

ObjectAnimator flyFromLtoR2 = GiftAnimationUtil.createFlyFromLtoR(anim_gift, -getWidth(), 0, 400,new DecelerateInterpolator());

flyFromLtoR2.addListener(new AnimatorListenerAdapter() {

@Override

public void onAnimationStart(Animator animation) {

anim_gift.setVisibility(View.VISIBLE);

}

@Override

public void onAnimationEnd(Animator animation) {

GiftAnimationUtil.startAnimationDrawable(anim_light);

anim_num.setVisibility(View.VISIBLE);

}

});

//数量增加

ObjectAnimator scaleGiftNum = GiftAnimationUtil.scaleGiftNum(anim_num, repeatCount);

scaleGiftNum.addListener(new AnimatorListenerAdapter() {

@Override

public void onAnimationRepeat(Animator animation) {

anim_num.setText("x " + (++starNum));

}

});

//向上渐变消失

ObjectAnimator fadeAnimator = GiftAnimationUtil.createFadeAnimator(GiftFrameLayout.this, 0, -100, 300, 400);

fadeAnimator.addListener(new AnimatorListenerAdapter() {

@Override

public void onAnimationEnd(Animator animation) {

GiftFrameLayout.this.setVisibility(View.INVISIBLE);

}

});

// 复原

ObjectAnimator fadeAnimator2 = GiftAnimationUtil.createFadeAnimator(GiftFrameLayout.this, 100, 0, 20, 0);

AnimatorSet animatorSet = GiftAnimationUtil.startAnimation(flyFromLtoR, flyFromLtoR2, scaleGiftNum, fadeAnimator, fadeAnimator2);

animatorSet.addListener(new AnimatorListenerAdapter() {

@Override

public void onAnimationEnd(Animator animation) {

starNum = 1;

isShowing = false;

}

});

return animatorSet;

我们将所有的动画方法都写到了GiftAnimationUtil中便于管理

public class GiftAnimationUtil {

/**

* @param target

* @param star 动画起始坐标

* @param end 动画终止坐标

* @param duration 持续时间

* @return

* 创建一个从左到右的飞入动画

* 礼物飞入动画

*/

public static ObjectAnimator createFlyFromLtoR(final View target, float star, float end, int duration, TimeInterpolator interpolator) {

//1.个人信息先飞出来

ObjectAnimator anim1 = ObjectAnimator.ofFloat(target, "translationX",

star, end);

anim1.setInterpolator(interpolator);

anim1.setDuration(duration);

return anim1;

}

/**

* @param target

* @return

* 播放帧动画

*/

public static AnimationDrawable startAnimationDrawable(ImageView target){

AnimationDrawable animationDrawable = (AnimationDrawable) target.getDrawable();

if(animationDrawable!=null) {

target.setVisibility(View.VISIBLE);

animationDrawable.start();

}

return animationDrawable;

}

/**

* @param target

* @param drawable

* 设置帧动画

*/

public static void setAnimationDrawable(ImageView target, AnimationDrawable drawable){

target.setBackground(drawable);

}

/**

* @param target

* @param num

* @return

* 送礼数字变化

*/

public static ObjectAnimator scaleGiftNum(final TextView target , int num){

PropertyValuesHolder anim4 = PropertyValuesHolder.ofFloat("scaleX",

1.7f, 0.8f,1f);

PropertyValuesHolder anim5 = PropertyValuesHolder.ofFloat("scaleY",

1.7f, 0.8f,1f);

PropertyValuesHolder anim6 = PropertyValuesHolder.ofFloat("alpha",

1.0f, 0f,1f);

ObjectAnimator animator = ObjectAnimator.ofPropertyValuesHolder(target, anim4, anim5, anim6).setDuration(480);

animator.setRepeatCount(num);

return animator;

}

/**

* @param target

* @param star

* @param end

* @param duration

* @param startDelay

* @return

* 向上飞 淡出

*/

public static ObjectAnimator createFadeAnimator(final View target, float star, float end, int duration, int startDelay){

PropertyValuesHolder translationY = PropertyValuesHolder.ofFloat("translationY", star,end);

PropertyValuesHolder alpha = PropertyValuesHolder.ofFloat("alpha", 1.0f,0f);

ObjectAnimator animator = ObjectAnimator.ofPropertyValuesHolder(target, translationY, alpha);

animator.setStartDelay(startDelay);

animator.setDuration(duration);

return animator;

}

/**

* @param animators

* @return

* 按顺序播放动画

*/

public static AnimatorSet startAnimation(ObjectAnimator animator1, ObjectAnimator animator2, ObjectAnimator animator3, ObjectAnimator animator4, ObjectAnimator animator5){

AnimatorSet animSet = new AnimatorSet();

// animSet.playSequentially(animators);

animSet.play(animator1).before(animator2);

animSet.play(animator3).after(animator2);

animSet.play(animator4).after(animator3);

animSet.play(animator5).after(animator4);

animSet.start();

return animSet;

}

}

所有的动画效果均是用属性动画完成,其中不仅有单个的动画,还有组合动画。属性动画用起来方面而且功能十分强大!

最后看下MainActivity中的实现

public class MainActivity extends AppCompatActivity {

private GiftFrameLayout giftFrameLayout1;

private GiftFrameLayout giftFrameLayout2;

List giftSendModelList = new ArrayList();

@Override

protected void onCreate(Bundle savedInstanceState) {

super.onCreate(savedInstanceState);

setContentView(R.layout.activity_main);

giftFrameLayout1 = (GiftFrameLayout) findViewById(R.id.gift_layout1);

giftFrameLayout2 = (GiftFrameLayout) findViewById(R.id.gift_layout2);

findViewById(R.id.action).setOnClickListener(new View.OnClickListener() {

@Override

public void onClick(View view) {

starGiftAnimation(createGiftSendModel());

}

});

}

private GiftSendModel createGiftSendModel(){

return new GiftSendModel((int)(Math.random()*10));

}

private void starGiftAnimation(GiftSendModel model){

if (!giftFrameLayout1.isShowing()) {

sendGiftAnimation(giftFrameLayout1,model);

}else if(!giftFrameLayout2.isShowing()){

sendGiftAnimation(giftFrameLayout2,model);

}else{

giftSendModelList.add(model);

}

}

private void sendGiftAnimation(final GiftFrameLayout view, GiftSendModel model){

view.setModel(model);

AnimatorSet animatorSet = view.startAnimation(model.getGiftCount());

animatorSet.addListener(new AnimatorListenerAdapter() {

@Override

public void onAnimationEnd(Animator animation) {

super.onAnimationEnd(animation);

synchronized (giftSendModelList) {

if (giftSendModelList.size() > 0) {

view.startAnimation(giftSendModelList.get(giftSendModelList.size() - 1).getGiftCount());

giftSendModelList.remove(giftSendModelList.size() - 1);

}

}

}

});

}

@Override

public boolean onCreateOptionsMenu(Menu menu) {

// Inflate the menu; this adds items to the action bar if it is present.

getMenuInflater().inflate(R.menu.menu_main, menu);

return true;

}

@Override

public boolean onOptionsItemSelected(MenuItem item) {

// Handle action bar item clicks here. The action bar will

// automatically handle clicks on the Home/Up button, so long

// as you specify a parent activity in AndroidManifest.xml.

int id = item.getItemId();

//noinspection SimplifiableIfStatement

if (id == R.id.action_settings) {

return true;

}

return super.onOptionsItemSelected(item);

}

}

其中关于缓存区的策略大家可以根据实际需求进行定制。

以上所述是小编给大家介绍的Android开发仿映客送礼物效果,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对脚本之家网站的支持!

android动画送礼物,Android开发仿映客送礼物效果相关推荐

  1. 映客都是互刷礼物吗_仿映客刷礼物效果 代码优化

    上一篇文章<仿映客刷礼物效果---基本逻辑实现>中,分析了刷礼物效果的基本流程与具体实现代码.但还有一些BUG和一些可优化的地方没有处理,现在我们就来分析下这些遗留的问题.当然个人的能力是 ...

  2. 映客都是互刷礼物吗_仿映客刷礼物效果---代码优化

    上一篇文章<仿映客刷礼物效果---基本逻辑实现>中,分析了刷礼物效果的基本流程与具体实现代码.但还有一些BUG和一些可优化的地方没有处理,现在我们就来分析下这些遗留的问题.当然个人的能力是 ...

  3. 映客都是互刷礼物吗_仿映客刷礼物效果—基本逻辑实现

    项目介绍: 最近做了个直播项目,需要用到弹幕和刷礼物.在网上找了许多开源代码,发现都不是很适合自己的项目需求,于是利用空余时间将两个功能都实现下,这里分享出来,供大家一起学习.(关于弹幕的实现,大家可 ...

  4. 映客都是互刷礼物吗_iOS 动画队列—仿映客刷礼物效果

    最近在研究直播的相关知识,在网上看到了不少优秀的开源项目,但都没有看到映客那个刷礼物的效果,于是手痒痒,决定自己做一个. 1. 首先从简单的开始,文字描边+连击效果,这个比较简单,只要重写 UILab ...

  5. 映客都是互刷礼物吗_iOS 基于 IM 实现仿映客刷礼物连击效果

    这里实现了以下功能:随着收到 IM 礼物消息,实时累加礼物数量 如果超出连击时间,比如 3s ,则重新开始计数,从 1 开始 如果在连击时间内,则在原先基础上累加 下面把改造思路跟大家分享下: 问题一 ...

  6. 最新仿映客直播APP开发实战项目IOS开发实战8天(最全最新)

    最新仿映客直播APP开发实战项目IOS开发实战8天 第 1 章:直播准备 1: [录播] 课程大纲介绍 09:56 2: [录播] 了解直播技术和腾讯云直播 09:54 3: [录播] 基础封装 23 ...

  7. 如何开发出一款仿映客直播APP项目实践篇 -【服务器搭建+推流】

    如何开发出一款仿映客直播APP项目实践篇 -[原理篇] 如何开发出一款仿映客直播APP项目实践篇 -[采集篇 ] 如何开发出一款仿映客直播APP项目实践篇 -[服务器搭建+推流] 如何开发出一款仿映客 ...

  8. Objective-C仿映客跑车动画

    做了一个仿映客跑车动画,效果就是边跑边放大,过程中车轮子也在转.先来看一下效果: 大体的思路就是把汽车和轮子图片放大一个view中,给这个view加上改变位置和大小的动画,同时,车轮子自己执行tran ...

  9. Android动画(图片闪烁、左右摇摆、上下晃动等效果)

    Android动画(图片闪烁.左右摇摆.上下晃动等效果) 通常我们需要一个item连续的播放某一段动画或者循环的执行某个动画,这里我们就可以用到一下技巧. 一.续播 (不知道取什么名字好,就是先播放动 ...

最新文章

  1. QML的默认属性default property
  2. java与与短路与_Java中短路运算符与逻辑运算符示例详解
  3. 使用JUnit规则测试预期的异常
  4. VMware Workstation 8 技巧集
  5. k8s traefik 映射外部服务,映射其他域名,映射内网其他服务
  6. [luoguP1373] 小a和uim之大逃离(DP)
  7. excel处理html文件,html网页显示excel表格数据-html读取本地excel文件并展示
  8. linux局域网连接网络打印机驱动程序,EBS on linux 网络打印机配置
  9. 双态运维联盟(BOA)正式成立
  10. Steve Jobs Said
  11. 7-8 哈利·波特的考试,7-9 旅游规划,7-10 公路村村通
  12. [论文笔记] ASFD 阅读笔记
  13. 【转】给大家分享一下目前mlc颗粒的内存卡资料
  14. Facebook背后的软件
  15. Handler源码分析 - Java层
  16. 区块链对抑制公共部门的腐败有什么作用?
  17. SRM 504.5 DIV2
  18. Windows系统中LOL登陆错误出现的服务器未响应优化教程
  19. Linux操作环境变量 getenv函数、setenv函数、unsetenv函数使用
  20. 计算机专业英语谐音读法,英语48个音标中文谐音读法大全

热门文章

  1. ps滚动字教程:为图像画面添加滚动字幕
  2. final cut pro 最快速,最简单的批量字幕制作方法!
  3. 华为云EI的诗与远方
  4. java基础知识面试题(41-95)
  5. autoJS for 快手极速版 可运行
  6. 学术与应用的碰撞,精准医疗和生物医药大数据的盛宴
  7. 什么是RC版本(转载)
  8. Html网站页面实现黑白效果
  9. Debian10英语环境安装搜狗输入法
  10. Google Docs Viewer在线打开阅读PDF、Word、PPT、Excel等