Android仿直播特效之刷礼物
来源:互联网 发布:网络写手兼职招聘 编辑:程序博客网 时间:2024/05/19 04:03
一、概述
继续咱们的直播之旅,过段时间再把推流拉流写上博客,暂时还是UI特效,先上图
二、创建我们的BaseActivity和BaseFrag
/** * @author 刘洋巴金 * @date 2017-5-3 * * 基类 * */public abstract class BaseActivity extends FragmentActivity implements OnClickListener{@Overrideprotected void onCreate(Bundle savedInstanceState) {// TODO Auto-generated method stubsuper.onCreate(savedInstanceState);setContentView(getLayoutId());initBase();initView();initData();initListener();}/** * 设置子类getLayoutId * */public abstract int getLayoutId();/** * 基类初始化 * */public void initBase() {}/** * 子类初始化View * */public void initView() {}/** * 子类初始化数据 * */public void initData() {}/** * 子类初始化监听 * */public void initListener() {}@Overridepublic void onClick(View v) {}}
baseFrag
/** * @author 刘洋巴金 * @date 2017-5-3 * * Frag基类 * */public abstract class BaseFrag extends Fragment implements OnClickListener{public View view;public Context myContext;@Overridepublic View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {view = inflater.inflate(getLayoutId(), null);// 初始化initBase();initView();initData();initListener();return view;}/** * 设置子类getLayoutId * */public abstract int getLayoutId();/** * 基类初始化 * */public void initBase() {myContext = getActivity();}/** * 子类初始化View * */public void initView() {}/** * 子类初始化数据 * */public void initData() {}/** * 子类初始化监听 * */public void initListener() {}@Overridepublic void onClick(View v) {}}和baseActivity差不多这个就是我们的基类,然后是我们的主类
/** * @author 刘洋巴金 * @date 2017-5-3 * * 主页 * */public class MainActivity extends BaseActivity {@Overridepublic int getLayoutId() {return R.layout.activity_main;}@Overridepublic void initData() {super.initData();// 加载直播fragmentLiveFrag liveFrag = new LiveFrag();getSupportFragmentManager().beginTransaction().add(R.id.fl_root, liveFrag).commit(); // 加载new InteractiveFrag().show(getSupportFragmentManager(), "InteractiveFrag");}}经过封装简单了很多吧?然后是加载fragment,LiveFrag就是我们的直播frag,现在目前为止就是一个图片,以后增加拉流等相关功能,然后加载我们的用户交互InteractiveFrag。
它是继承DialogFragment,这个不明白的可以百度查询,而这个也不是必须,可以自定义,
这里最主要的逻辑就是加了一个viewpager, 共加载了2个fragment,一个是我们交互用的,一个是透明的,这样是为了滑动隐藏我们的交互的功能,如上图最后的操作。EmptyFrag背景设置为透明,无任何逻辑
/** * 观众功能交互页面, 滑动隐藏效果 * * @author 刘洋巴金 * @date 2017-5-3 */public class InteractiveFrag extends DialogFragment{public View view;public Context myContext;private ViewPager vp_interactive;private LayerFrag layerFrag;@Overridepublic View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {view = inflater.inflate(R.layout.frag_interactive, null);// 初始化initView();initData();initListener();return view;}/** * 初始化View * */public void initView() {vp_interactive = (ViewPager)view.findViewById(R.id.vp_interactive);}/** * 初始化数据 * */public void initData() { // EmptyFrag:什么都没有 // LayerFrag:交互界面 // 这样就达到了滑动隐藏交互的需求vp_interactive.setAdapter(new FragmentPagerAdapter(getChildFragmentManager()) {@Overridepublic int getCount() {return 2;}@Overridepublic Fragment getItem(int position) {if (position == 0){return new EmptyFrag(); // 返回空界面的fragment}else if (position == 1){return layerFrag = new LayerFrag(); // 返回交互界面的frag}else{ // 设置默认return new EmptyFrag();}}});// 设置默认显示交互界面vp_interactive.setCurrentItem(1);// 同时将界面改为resize已达到软键盘弹出时Fragment不会跟随移动getDialog().getWindow().setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_ADJUST_RESIZE);}/** * 初始化监听 * */public void initListener() {vp_interactive.setOnPageChangeListener(new OnPageChangeListener() {@Overridepublic void onPageSelected(int position) {if(position == 0){//layerFrag.hideKeyboard();}}@Overridepublic void onPageScrolled(int position, float arg1, int arg2) {}@Overridepublic void onPageScrollStateChanged(int position) {}});} @Override public Dialog onCreateDialog(Bundle savedInstanceState) { // 设置DialogFragment的样式,这里的代码最好还是用我的,大家不要改动 Dialog dialog = new Dialog(getActivity(), R.style.MainDialog){ @Override public void onBackPressed() { super.onBackPressed(); getActivity().finish(); } }; return dialog; }}三、实现我们的交互页面
/** * 用户交互页 * * @author 刘洋巴金 * @date 2017-5-3 */public class LayerFrag extends BaseFrag{private NumberAnim giftNumberAnim; private List<String> messageData = new LinkedList<>();private MessageAdapter messageAdapter;private ListView lv_message;private HorizontalListView hlv_audience;private LinearLayout ll_gift_group;private TranslateAnimation outAnim;private TranslateAnimation inAnim;private LinearLayout ll_inputparent;private Button tv_chat;private EditText et_chat;private LinearLayout ll_anchor;private RelativeLayout rl_num; @Overridepublic int getLayoutId() {// TODO Auto-generated method stubreturn R.layout.frag_layer;}@Overridepublic void initView() {// TODO Auto-generated method stubsuper.initView();lv_message = (ListView)view.findViewById(R.id.lv_message);hlv_audience = (HorizontalListView)view.findViewById(R.id.hlv_audience);ll_gift_group = (LinearLayout)view.findViewById(R.id.ll_gift_group);ll_inputparent = (LinearLayout)view.findViewById(R.id.ll_inputparent);tv_chat = (Button)view.findViewById(R.id.tv_chat);et_chat = (EditText)view.findViewById(R.id.et_chat);ll_anchor = (LinearLayout)view.findViewById(R.id.ll_anchor);rl_num = (RelativeLayout)view.findViewById(R.id.rl_num);}@Overridepublic void initData() {// TODO Auto-generated method stubsuper.initData();initAudience(); // 初始化观众initMessage(); // 初始化评论clearTiming(); // 开启定时清理礼物列表initAnim(); // 初始化动画}
进行初始化和变量声明,首先初始化右上角的观众,其实就是个GridView,这里不再概述/** * 初始化观众列表 * */private void initAudience() {hlv_audience.setAdapter(new AudienceAdapter(myContext));}然后初始化评论,左下角底部的评论列表,listview不再概述
/** * 初始化评论列表 * */private void initMessage() { for(int x = 0; x < 20; x++){ messageData.add("刘洋巴金: 主播好漂亮啊" + x); } messageAdapter = new MessageAdapter(getActivity(), messageData); lv_message.setAdapter(messageAdapter); lv_message.setSelection(messageData.size());}初始化动画
/** * 初始化动画 * */private void initAnim() {giftNumberAnim = new NumberAnim(); // 初始化数字动画inAnim = (TranslateAnimation) AnimationUtils.loadAnimation(getActivity(), R.anim.gift_in); // 礼物进入时动画 outAnim = (TranslateAnimation) AnimationUtils.loadAnimation(getActivity(), R.anim.gift_out); // 礼物退出时动画}
礼物的数字动画,就是简单的放大
/** * 送的礼物后面的数字动画 * */public class NumberAnim{private Animator lastAnimator;public void showAnimator(View v){if (lastAnimator != null) {lastAnimator.removeAllListeners();lastAnimator.cancel();lastAnimator.end();}ObjectAnimator animScaleX = ObjectAnimator.ofFloat(v, "scaleX", 1.3f, 1.0f);ObjectAnimator animScaleY = ObjectAnimator.ofFloat(v, "scaleY", 1.3f, 1.0f);AnimatorSet animSet = new AnimatorSet();animSet.playTogether(animScaleX, animScaleY);animSet.setDuration(200);lastAnimator = animSet;animSet.start();}}设置礼物的动画集合,使它放大1.3倍
clearTiming为礼物清理,3秒后自动清理,这个放在后面讲,先开始刷礼物
@Overridepublic void onClick(View v) {// TODO Auto-generated method stubsuper.onClick(v);switch (v.getId()) { case R.id.btn_gift01: // 礼物1,送香皂 showGift("gift01"); break; case R.id.btn_gift02: // 礼物2,送玫瑰 showGift("gift02"); break; case R.id.btn_gift03: // 礼物3,送爱心 showGift("gift03"); break; case R.id.btn_gift04: // 礼物4,送蛋糕 showGift("gift04"); break;4个按钮的点击事件
然后是刷礼物
/** * 刷礼物 * */private void showGift(String tag) {View newGiftView = ll_gift_group.findViewWithTag(tag);// 是否有该tag类型的礼物if(newGiftView == null){// 判断礼物列表是否已经有3个了,如果有那么删除掉一个没更新过的, 然后再添加新进来的礼物,始终保持只有3个if(ll_gift_group.getChildCount() >= 3){// 获取前2个元素的最后更新时间View giftView01 = ll_gift_group.getChildAt(0);ImageView iv_gift01 = (ImageView)giftView01.findViewById(R.id.iv_gift);long lastTime1 = (long) iv_gift01.getTag();View giftView02 = ll_gift_group.getChildAt(1);ImageView iv_gift02 = (ImageView)giftView02.findViewById(R.id.iv_gift);long lastTime2 = (long) iv_gift02.getTag();if (lastTime1 > lastTime2) { // 如果第二个View显示的时间比较长 removeGiftView(1); } else { // 如果第一个View显示的时间长 removeGiftView(0); }}// 获取礼物newGiftView = getNewGiftView(tag);ll_gift_group.addView(newGiftView);// 播放动画newGiftView.startAnimation(inAnim);final MagicTextView mtv_giftNum = (MagicTextView) newGiftView.findViewById(R.id.mtv_giftNum);inAnim.setAnimationListener(new AnimationListener() {@Overridepublic void onAnimationStart(Animation animation) {}@Overridepublic void onAnimationRepeat(Animation animation) {}@Overridepublic void onAnimationEnd(Animation animation) {// TODO Auto-generated method stubgiftNumberAnim.showAnimator(mtv_giftNum);}});}else{...}}1.这段是核心代码,首先评论去上方我们定义了一个LinearLayout,ll_gift_group,
2.然后根据点击事件传入tag,在ll_gift_group查询是否有该tag的子控件,也就是是否有该种类的礼物,如果没有,判断当前不同种类是否已经3个了,如果是,那么移除一个最先更新的礼物。
3.位置空出来了,生成我们的礼物
/** * 获取礼物 * */private View getNewGiftView(String tag) {// 添加标识, 该view若在layout中存在,就不在生成(用于findViewWithTag判断是否存在)View giftView = LayoutInflater.from(myContext).inflate(R.layout.item_gift, null);giftView.setTag(tag); // 添加标识, 记录生成时间,回收时用于判断是否是最新的,回收最老的ImageView iv_gift = (ImageView)giftView.findViewById(R.id.iv_gift);iv_gift.setTag(System.currentTimeMillis());// 添加标识,记录礼物个数MagicTextView mtv_giftNum = (MagicTextView) giftView.findViewById(R.id.mtv_giftNum);mtv_giftNum.setTag(1);mtv_giftNum.setText("x1"); switch (tag){ case "gift01": iv_gift.setImageResource(GiftIcon[0]); break; case "gift02": iv_gift.setImageResource(GiftIcon[1]); break; case "gift03": iv_gift.setImageResource(GiftIcon[2]); break; case "gift04": iv_gift.setImageResource(GiftIcon[3]); break; } LinearLayout.LayoutParams lp = new LinearLayout.LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT); lp.topMargin = 10; giftView.setLayoutParams(lp); return giftView;}1.生成我们的礼物控件,然后绑定tag进行标识,就是点击事件传递过来的tag,
2.找其子控件,再绑定更新时间,因为要回收更新最早的控件,保留最后更新的
3.找其子控件,添加标识,记录该种礼物的个数
4.设置礼物图片
5.设置大小返回
好继续回到我们的showGift方法
4.生成礼物后,添加到 ll_gift_group中,并执行进入动画,MagicTextView为我们自定义的礼物数量的字体样式,这个没有规定可随意自定义
5.礼物进入动画执行完毕后,再执行数字动画,就是放大
好了,然后我们又刷了一个礼物。
根据
View newGiftView = ll_gift_group.findViewWithTag(tag);判读是否该类型的礼物还没有被清理掉
如果是,那么我们走else
View newGiftView = ll_gift_group.findViewWithTag(tag);// 是否有该tag类型的礼物if(newGiftView == null){...}else{// 如果列表中已经有了该类型的礼物,则不再新建,直接拿出// 更新标识,记录最新修改的时间,用于回收判断ImageView iv_gift = (ImageView)newGiftView.findViewById(R.id.iv_gift);iv_gift.setTag(System.currentTimeMillis());// 更新标识,更新记录礼物个数 MagicTextView mtv_giftNum = (MagicTextView) newGiftView.findViewById(R.id.mtv_giftNum);int giftCount = (int) mtv_giftNum.getTag() + 1; // 递增 mtv_giftNum.setText("x" + giftCount); mtv_giftNum.setTag(giftCount);giftNumberAnim.showAnimator(mtv_giftNum);}1.首先拿出礼物控件的子控件,更新它的更新时间
2.然后再拿出其子控件更新他的礼物数量的标识。
3.更改UI,执行数字动画
这样礼物就刷出去了,但是为了用户体验,礼物要3秒钟之后消失
/** * 定时清理礼物列表信息 */private void clearTiming() { Timer timer = new Timer(); timer.schedule(new TimerTask() { @Override public void run() {int childCount = ll_gift_group.getChildCount();long nowTime = System.currentTimeMillis();for (int i = 0; i < childCount; i++) {View childView = ll_gift_group.getChildAt(i); ImageView iv_gift = (ImageView)childView.findViewById(R.id.iv_gift);long lastUpdateTime = (long) iv_gift.getTag();// 更新超过3秒就刷新if(nowTime - lastUpdateTime >= 3000){removeGiftView(i);}}} }, 0, 3000);}这个就比较简单了,拿出 ll_gift_group中全部的控件,遍历他们,取出他们最后更新的时间,然后对比当前时间,如果谁的时间超过3秒了,那么执行移除
/** * 移除礼物列表里的giftView * */private void removeGiftView(final int index) {// 移除列表,外加退出动画final View removeGiftView = ll_gift_group.getChildAt(index);outAnim.setAnimationListener(new AnimationListener() {@Overridepublic void onAnimationStart(Animation animation) {}@Overridepublic void onAnimationRepeat(Animation animation) {}@Overridepublic void onAnimationEnd(Animation animation) {// TODO Auto-generated method stubll_gift_group.removeViewAt(index);}});// 开启动画,因为定时原因,所以可能是在子线程getActivity().runOnUiThread(new Runnable() {@Overridepublic void run() {removeGiftView.startAnimation(outAnim);}});}移除礼物,然后执行退出动画。
好了刷礼物就到这吧,不明白的话,底下评论
四、demo
Android仿直播特效之刷礼物
1 0
- Android仿直播特效之刷礼物
- Android仿直播特效之点赞飘心
- 仿照映客的直播界面的刷礼物效果
- android直播app礼物连击动画效果
- jquery仿直播app按钮点赞特效
- android listview仿iphone特效
- android listview仿iphone特效
- android开发技巧——直播礼物面板制作
- 直播礼物系统设计
- Android 特效直播实现原理解析
- Android开发之贝塞尔曲线进阶篇(仿直播送礼物,饿了么购物车动画)
- 直播-动态礼物(豪华礼物)
- 仿写礼物说
- android listview仿iphone弹簧特效
- android listview仿iphone弹簧特效
- android listview仿iphone弹簧特效
- Android 特效库 - 仿QQ汽泡
- Android仿QQ聊天撒花特效
- android studio xml 快捷键设置
- 【C/C++开发】TinyXml操作(含源码下载)
- 远程部署war包项目遇到的问题解决方案
- 笔记--
- Spring3.x事务失效的原因以及解决办法
- Android仿直播特效之刷礼物
- bzoj 3998 [TJOI2015]弦论
- [Java并发包学习二]Executors介绍
- DUBBO服务管理配置Zookeeper集群服务
- C#初学者对Equals方法的几个常见误解
- [安卓] 13、安卓蓝牙定位(一)——如何周期性获得蓝牙节点信号强度?
- 数据链路层循环冗余(CRC)检验
- 【C/C++开发】C++实现字符串替换的两种方法
- 扩展欧几里得算法