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
原创粉丝点击