Android开发仿映客送礼物效果

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

需求分析

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

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

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

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

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

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

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

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

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

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

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

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

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

功能实现

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

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

<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:app="http://schemas.android.com/apk/res-auto" android:layout_width="match_parent" android:layout_height="wrap_content"> <RelativeLayout 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"> <ImageView 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" /> <TextView 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" /> <TextView 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" /> <ImageView 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" /> </RelativeLayout> <ImageView 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" /> <com.example.work.animationdemo.StrokeTextView 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" /> </FrameLayout>

这里比较简单不多说了,重点看下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<GiftSendModel> giftSendModelList = new ArrayList<GiftSendModel>(); @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开发仿映客送礼物效果,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对脚本之家网站的支持!

时间: 2024-09-23 17:58:41

Android开发仿映客送礼物效果的相关文章

Android开发仿映客送礼物效果_Android

这里写链接内容仿映客送小礼物的特效,顺便复习一下属性动画,话不多说先看效果图. 需求分析 可以看到整个动画有几部分组成,那我们就把每个部分拆分出来各个击破. 1.要显示那些内容以及内容间的位置关系? 可以看到我们要显示用户头像,昵称,礼物图标以及数量.所以这里我选择用FrameLayout来作为根布局. 2.需要哪些动画以及动画的执行顺序? a.首先是整体从左到右飞入并有一个回弹(translationX + OvershootInterpolator) b.然后是礼物从左到右飞入而且是一个带减

Android开发仿QQ空间根据位置弹出PopupWindow显示更多操作效果_Android

我们打开QQ空间的时候有个箭头按钮点击之后弹出PopupWindow会根据位置的变化显示在箭头的上方还是下方,比普通的PopupWindow弹在屏幕中间显示好看的多. 先看QQ空间效果图: 这个要实现这个效果可以分几步进行 1.第一步自定义PopupWindow,实现如图的样式,这个继承PopupWindow自定义布局很容易实现 2.得到点击按钮的位置,根据位置是否在屏幕的中间的上方还是下方,将PopupWindow显示在控件的上方或者下方 3.适配问题,因为PopupWindow上面的操作列表

Android开发仿QQ空间根据位置弹出PopupWindow显示更多操作效果

我们打开QQ空间的时候有个箭头按钮点击之后弹出PopupWindow会根据位置的变化显示在箭头的上方还是下方,比普通的PopupWindow弹在屏幕中间显示好看的多. 先看QQ空间效果图: 这个要实现这个效果可以分几步进行 1.第一步自定义PopupWindow,实现如图的样式,这个继承PopupWindow自定义布局很容易实现 2.得到点击按钮的位置,根据位置是否在屏幕的中间的上方还是下方,将PopupWindow显示在控件的上方或者下方 3.适配问题,因为PopupWindow上面的操作列表

仿映客视频直播

原文链接:http://www.jianshu.com/p/5b1341e97757 一.直播现状简介 Linkee.10 1.技术实现层面: 技术相对都比较成熟,设备也都支持硬编码.IOS还提供现成的 Video ToolBox框架,可以对摄像头和流媒体数据结构进行处理,但Video ToolBox框架只兼容8.0以上版本,8.0以下就需要用x264的库软编了. github上有现成的开源实现,推流.美颜.水印.弹幕.点赞动画.滤镜.播放都有.技术其实不是很难,而且现在很多云厂商都提供SDK,

Android开发仿扫一扫实现拍摄框内的照片功能_Android

就是仿照现在扫一扫的形式,周围是半透明的遮挡,然后中间是全透明的,拍摄后只截取框内的内容 查了很多博客,实现起来真的太复杂了,本人比较怕麻烦所以在很多地方偷懒了 先上效果图: 第一步:设置照相机预览以及拍照 这是所有步骤的前提,没有预览,用户怎么知道自己拍的什么呢.预览用的是SurfaceView 这篇博文写得已经十分详细了,打开照相机,然后拍照,而且十分简洁!不想别的博客一下就几百行代码不知所云.这篇代码可以复制下去当相机模版使用. 这里遇到一个问题,就是预览的效果是左转90度的,拍出来也是左

Android开发仿扫一扫实现拍摄框内的照片功能

就是仿照现在扫一扫的形式,周围是半透明的遮挡,然后中间是全透明的,拍摄后只截取框内的内容 查了很多博客,实现起来真的太复杂了,本人比较怕麻烦所以在很多地方偷懒了 先上效果图: 第一步:设置照相机预览以及拍照 这是所有步骤的前提,没有预览,用户怎么知道自己拍的什么呢.预览用的是SurfaceView 这篇博文写得已经十分详细了,打开照相机,然后拍照,而且十分简洁!不想别的博客一下就几百行代码不知所云.这篇代码可以复制下去当相机模版使用. 这里遇到一个问题,就是预览的效果是左转90度的,拍出来也是左

基于jQuery实现仿QQ空间送礼物功能代码_jquery

我们在QQ空间里面有一个送礼物的功能,显示了最近过生日的人.我们只要把鼠标放到如下图的生日快乐那标签上,就会显示可以给该人送的礼物!! 如下图所示: 单击其中的一个礼物,就会马上送出去.但是我们现在是要说的还有单击更多的时候,会另外弹出一个新的窗口在当前页面最前面!如下图显示: 怎么实现那上面的功能呢? 就是把鼠标放上去,弹出一天tips,单击tips里面的控件,之后弹出另外一个弹出框. 网上就会有很多比较好的插件,就先到网上去找了相对应的jquery插件. jquery中tips的有很多插件,

Android 开发仿简书登录框可删除内容或显示密码框的内容_Android

简书App 是我很喜欢的一款软件.今天就模仿了一下他的登录框.先上图: 好了下面上代码,自定义ImgEditText 继承与EditText.重写一些方法. package lyf.myimgedittextdemo; import android.content.Context; import android.graphics.Rect; import android.graphics.drawable.Drawable; import android.text.Editable; impor

Android实现仿通讯录侧边栏滑动SiderBar效果代码_Android

本文实例讲述了Android实现仿通讯录侧边栏滑动SiderBar效果代码.分享给大家供大家参考,具体如下: 之前看到某些应用的侧边栏做得不错,想想自己也弄一个出来,现在分享出来,当然里面还有不足的地方,请大家多多包涵. 先上图: 具体实现的代码如下: package com.freesonfish.listview_index; import android.content.Context; import android.graphics.Canvas; import android.grap