一、概述

现在有个很流行的效果就是弹幕效果,满屏幕的文字从右到左飘来飘去。看的眼花缭乱,看起来还蛮cool的

现在就是来实现这一的一个效果,大部分的都是从右向左移动漂移,本文的效果中也支持从左向右的漂移移动

效果,同时也支持屏幕弹幕最多显示个数的设置。

二、效果图

废话不说,先来看看效果图吧~~

三、实现原理方案

1、自定义ViewGroup-XCDanmuView,继承RelativeLayout来实现,当然也可以继承其他三大布局类哈

2、初始化若干个TextView(弹幕的item View,这里以TextView 为例,当然也可以其他了~),然后通过addView添加到自定义View中

3、通过addView添加到XCDanmuView中,位置在坐标,为了实现 从屏幕外移动进来的效果

我们还需要修改添加进来TextView的位置,以从右向左移动方向来说,addView后必须将该TextView的位置设置到右边的屏幕外

这样我们采用的方法,是在onLayout()方法中对childView进行layout重新布局设置位置

4、随机冲左侧或右侧出来弹幕itemView,移动采用属性动画来实现平移,从屏幕的一端移动到另一端,当动画结束后,就将

该child从XCDanmuView中remove掉。并重新new 一个弹幕itemView ,并addView到XCDanmuView中,并开始动画移动

5、本自定义弹幕View支持从左到右和从右到左两个方向,支持自定义设置屏幕弹幕最多显示个数。

四、自定义弹幕效果XCDanmuView的具体实现

1、初始化需要用到的数据变量

  1. private int mWidth;
  2. private int mScreenWidth;
  3. private List<View> mChildList;
  4. private boolean mIsWorking = false;
  5. private Context mContext;
  6. private int mMaxShowNum = 15;
  7. private int mRowNum = 4;
  8. private int[] mSpeeds = {
  9. 3000,4000,5000,6000
  10. };
  11. private int mDelayDuration = 500;
  12. private int[] mBgResIds = {
  13. R.drawable.bg_danmu0,
  14. R.drawable.bg_danmu1,
  15. R.drawable.bg_danmu2,
  16. R.drawable.bg_danmu3
  17. };
  18. private int[] mRowPos = {
  19. 150,140,160,150
  20. };
  21. private Random mRandom;
  22. private String[] mStrContents;
  23. public static enum XCDirection{
  24. FROM_RIGHT_TO_LEFT,
  25. FORM_LEFT_TO_RIGHT
  26. }
  27. public enum XCAction{
  28. SHOW,HIDE
  29. }
  30. private XCDirection mDirection = XCDirection.FROM_RIGHT_TO_LEFT;
  1.   private void init() {
    mScreenWidth = getScreenWidth();
    mChildList = new ArrayList<>();
    mRandom = new Random();
    }

2、初始化若干个弹幕item view

  1. public void initDanmuItemViews(String[] strContents){
  2. mStrContents = strContents;
  3. for(int i = 0; i < mMaxShowNum; i ++){
  4. int index = mRandom.nextInt(100) % strContents.length;
  5. createDanmuView(i,strContents[index],false);
  6. }
  7. }

3、创建弹幕item view 并addView到XCDanmuView中

  1. public void createDanmuView(int index,String content,boolean reset){
  2. final TextView textView = new TextView(mContext);
  3. textView.setTextColor(Color.WHITE);
  4. int r = mRandom.nextInt(100) % mRowNum;
  5. textView.setBackgroundResource(mBgResIds[r]);
  6. textView.setText(content +"_"+ (index+1));
  7. RelativeLayout.LayoutParams lp = new LayoutParams(LayoutParams.WRAP_CONTENT,
  8. RelativeLayout.LayoutParams.WRAP_CONTENT);
  9. int row = mRandom.nextInt(100) % mRowNum;
  10. while(row == lastRow){
  11. row = mRandom.nextInt(100)% mRowNum;
  12. }
  13. int pos = mRandom.nextInt(100)% mRowNum;
  14. lp.topMargin = row * mRowPos[pos];
  15. lastRow = row;
  16. textView.setLayoutParams(lp);
  17. textView.setPadding(40, 2, 40, 2);
  18. this.addView(textView);
  19. if(reset){
  20. mChildList.set(index,textView);
  21. }else{
  22. mChildList.add(index,textView);
  23. }
  24. textView.setClickable(true);
  25. textView.setOnClickListener(new OnClickListener() {
  26. @Override
  27. public void onClick(View view) {
  28. Toast toast = Toast.makeText(mContext, textView.getText(), Toast.LENGTH_SHORT);
  29. toast.setGravity(Gravity.TOP,0,50);
  30. toast.show();
  31. }
  32. });
  33. }

4、重新设置childView的初始位置到屏幕之外

  1. @Override
  2. protected void onLayout(boolean changed, int l, int t, int r, int b) {
  3. super.onLayout(changed, l, t, r, b);
  4. int childCount = this.getChildCount();
  5. for(int i=0;i<childCount;i++){
  6. View view = getChildAt(i);
  7. RelativeLayout.LayoutParams lp = (LayoutParams) view.getLayoutParams();
  8. if(lp.leftMargin <= 0){
  9. if(mDirection == XCDirection.FORM_LEFT_TO_RIGHT){
  10. view.layout(-view.getMeasuredWidth(), lp.topMargin,
  11. 0,lp.topMargin + view.getMeasuredHeight());
  12. }else{
  13. view.layout(mScreenWidth,lp.topMargin,mScreenWidth+view.getMeasuredWidth(),
  14. lp.topMargin+view.getMeasuredHeight());
  15. }
  16.  
  17. }else{
  18. continue;
  19. }
  20. }
  21. }

5、弹幕item view的移动效果

  1. private Handler mHandler = new Handler() {
  2. @Override
  3. public void handleMessage(final Message msg) {
  4. super.handleMessage(msg);
  5. final int pos = msg.what;
  6. ViewPropertyAnimator animator;
  7. if(mDirection == XCDirection.FROM_RIGHT_TO_LEFT){
  8. animator = mChildList.get(msg.what).animate()
  9. .translationXBy(-(mScreenWidth + mChildList.get(msg.what).getWidth()));
  10. }else{
  11. animator = mChildList.get(msg.what).animate()
  12. .translationXBy(mScreenWidth + mChildList.get(msg.what).getWidth());
  13. }
  14.  
  15. Random random = new Random(System.currentTimeMillis());
  16. int index = random.nextInt(100) % mSpeeds.length;
  17. animator.setDuration(mSpeeds[index]);
  18. animator.setInterpolator(new LinearInterpolator());
  19. animator.setListener(new Animator.AnimatorListener() {
  20. @Override
  21. public void onAnimationStart(Animator animator) {
  22.  
  23. }
  24.  
  25. @Override
  26. public void onAnimationEnd(Animator animator) {
  27. XCDanmuView.this.removeView(mChildList.get(pos));
  28. int index = mRandom.nextInt(100) % mStrContents.length;
  29. createDanmuView(pos, mStrContents[index], true);
  30. mHandler.sendEmptyMessageDelayed(pos, mDelayDuration);
  31. Log.v("czm", "size=" + mChildList.size());
  32. }
  33.  
  34. @Override
  35. public void onAnimationCancel(Animator animator) {
  36.  
  37. }
  38.  
  39. @Override
  40. public void onAnimationRepeat(Animator animator) {
  41.  
  42. }
  43. });
  44. animator.start();
  45. }
  46. };

6、开启弹幕效果和关闭弹幕效果以及对于的动画效果

  1. boolean isFirst = true;
  2. public void start(){
  3. switchAnimation(XCAction.SHOW);
  4. if(isFirst){
  5. for(int i =0;i< mChildList.size();i++){
  6. mHandler.sendEmptyMessageDelayed(i,i * mDelayDuration);
  7. }
  8. isFirst = false;
  9. }
  10.  
  11. mIsWorking = true;
  12. }
  13. public void hide(){
  14. switchAnimation(XCAction.HIDE);
  15. mIsWorking =false;
  16. }
  17. public void stop(){
  18. this.setVisibility(View.GONE);
  19. for(int i =0;i< mChildList.size();i++){
  20. mChildList.get(i).clearAnimation();
  21. mHandler.removeMessages(i);
  22. }
  23. mIsWorking =false;
  24. }
  25. private void switchAnimation(final XCAction action){
  26. AlphaAnimation animation;
  27. if(action == XCAction.HIDE){
  28. animation = new AlphaAnimation(1.0f,0.0f);
  29. animation.setDuration(400);
  30. }else{
  31. animation = new AlphaAnimation(0.0f,1.0f);
  32. animation.setDuration(1000);
  33. }
  34. XCDanmuView.this.startAnimation(animation);
  35. animation.setAnimationListener(new Animation.AnimationListener() {
  36. @Override
  37. public void onAnimationStart(Animation animation) {
  38.  
  39. }
  40. @Override
  41. public void onAnimationEnd(Animation animation) {
  42. if(action == XCAction.HIDE){
  43. XCDanmuView.this.setVisibility(View.GONE);
  44. }else{
  45. XCDanmuView.this.setVisibility(View.VISIBLE);
  46. }
  47. }
  48. @Override
  49. public void onAnimationRepeat(Animation animation) {
  50.  
  51. }
  52. });
  53. }

五、如何使用该自定义侧滑View控件

使用该自定义View非常简单,控件默认效果从右向左,如果需要修改方向为从左到右,只需设置下方向即可

  1. public class MainActivity extends Activity {
  2.  
  3. private XCDanmuView mDanmuView;
  4. private List<View> mViewList;
  5. private String[] mStrItems = {
  6. "搜狗","百度",
  7. "腾讯","360",
  8. "阿里巴巴","搜狐",
  9. "网易","新浪",
  10. "搜狗-上网从搜狗开始","百度一下,你就知道",
  11. "必应搜索-有求必应","好搜-用好搜,特顺手",
  12. "Android-谷歌","IOS-苹果",
  13. "Windows-微软","Linux"
  14. };
  15. @Override
  16. protected void onCreate(Bundle savedInstanceState) {
  17. super.onCreate(savedInstanceState);
  18. setContentView(R.layout.activity_main);
  19. initDanmuView();
  20. initListener();
  21. }
  22.  
  23. private void initListener() {
  24. findViewById(R.id.btn).setOnClickListener(new View.OnClickListener() {
  25. @Override
  26. public void onClick(View view) {
  27. if (mDanmuView.isWorking()) {
  28. mDanmuView.hide();
  29. ((Button) view).setText("开启弹幕");
  30. } else {
  31. mDanmuView.start();
  32. ((Button) view).setText("关闭弹幕");
  33. }
  34. }
  35. });
  36. }
  37.  
  38. private void initDanmuView() {
  39. mDanmuView = (XCDanmuView)findViewById(R.id.danmu);
  40. mDanmuView.initDanmuItemViews(mStrItems);
  41. }
  42.  
  43. }

六、源码下载

源码下载http://www.demodashi.com/demo/13441.html

真题园网http://www.zhentiyuan.com

Android 自定义View修炼-自定义弹幕效果View的更多相关文章

  1. Android 自定义View修炼-自定义HorizontalScrollView视图实现仿ViewPager效果

    开发过程中,需要达到 HorizontalScrollView和ViewPager的效果,于是直接重写了HorizontalScrollView来达到实现ViewPager的效果. 实际效果图如下: ...

  2. Android 自定义View修炼-自定义View-带百分比进度的圆形进度条(采用自定义属性)

    很多的时候,系统自带的View满足不了我们功能的需求,那么我们就需要自己来自定义一个能满足我们需求的View,自定义View我们需要先继承View,添加类的构造方法,重写父类View的一些方法,例如o ...

  3. Android 自定义View修炼-自定义可动画展开收缩View的实现

    有时候需要点击一个view可以动画展开和收缩折叠一个View这样的效果,这样就可以直接自定义View来实现. 本例中,采用继承FrameLayout来实现自定义的ExpandView.下面将详细介绍各 ...

  4. Android 自定义View修炼-自定义加载进度动画XCLoadingImageView

    一.概述 本自定义View,是加载进度动画的自定义View,继承于ImageView来实现,主要实现蒙层加载进度的加载进度效果. 支持水平左右加载和垂直上下加载四个方向,同时也支持自定义蒙层进度颜色. ...

  5. Android 自定义View修炼-【2014年最后的分享啦】Android实现自定义刮刮卡效果View

    一.简介: 今天是2014年最后一天啦,首先在这里,我祝福大家在新的2015年都一个个的新健康,新收入,新顺利,新如意!!! 上一偏,我介绍了用Xfermode实现自定义圆角和椭圆图片view的博文& ...

  6. Android 自定义View修炼-打造完美的自定义侧滑菜单/侧滑View控件

    一.概述 在App中,经常会出现侧滑菜单,侧滑滑出View等效果,虽然说Android有很多第三方开源库,但是实际上 咱们可以自己也写一个自定义的侧滑View控件,其实不难,主要涉及到以下几个要点: ...

  7. Android 自定义View修炼-Android 实现自定义的卫星式菜单(弧形菜单)View

    一.总述 Android 实现卫星式菜单也叫弧形菜单的主要要做的工作如下:1.动画的处理2.自定义ViewGroup来实现卫星式菜单View (1)自定义属性       a. 在attrs.xml中 ...

  8. Android 自定义View修炼-仿360手机卫士波浪球进度的实现

    像360卫士的波浪球进度的效果,一般最常用的方法就是 画线的方式,先绘sin线或贝塞尔曲线,然后从左到右绘制竖线,然后再裁剪圆区域. 今天我这用图片bitmap的方式,大概的方法原理是: (1)首先用 ...

  9. Android 自定义View修炼-Android开发之自定义View开发及实例详解

    在开发Android应用的过程中,难免需要自定义View,其实自定义View不难,只要了解原理,实现起来就没有那么难. 其主要原理就是继承View,重写构造方法.onDraw,(onMeasure)等 ...

随机推荐

  1. SharePoint 2010 master page 控件介绍(1)

    转:http://blog.csdn.net/lgm97/article/details/6409204 以下所有的内容都是根据Randy Drisgill (MVP SharePoint Serve ...

  2. UPC OJ 一道水题 STL

    Problem C: 字符串游戏 Time Limit: 1 Sec  Memory Limit: 128 MB Submit: 10  Solved: 3 [Submit][Status][Web ...

  3. java 注解(转)

    第一部分:了解一下java1.5起默认的三个annotation类型:    一个是@Override:只能用在方法之上的,用来告诉别人这一个方法是改写父类的.    一个是@Deprecated:建 ...

  4. Android UI -- 的基础知识。

    在介绍基础知识之前先明确几个基本的概念 View 视图是所有可视组件的基类,所有的UI控件包括布局类都是从View派生出来的. ViewGroup ViewGroup是View的扩展,可以放置多个Vi ...

  5. 专门为公共部门和联邦机构所设计Microsoft Azure

    微软正式发布Microsoft Azure for Government,该云平台专门为公共部门和联邦机构所设计. 在2014年三月微软联邦执行官论坛上宣布的Microsoft Azure for G ...

  6. HW6.9

    import java.util.Scanner; public class Solution { public static void main(String[] args) { Scanner i ...

  7. QQMusic绿钻兄,你可安好?我需要晴天。

    不好意思,年纪这样大了,还依靠吐槽来保持呆毛的正能量,实在对不住,先说对不起. QQMusic是我最喜欢的腾讯增值服务,正版内容,海量歌手,高清下载.实在是音乐软件中高大上的典范,除了歌手排名中前十中 ...

  8. 科大讯飞和Tizen-TTS语音合成引擎

    最近在做一个文本转语音TTS(Text to Speech)的第三方软件封装,使用的是国内语音技术龙头安徽科大讯飞公司提供的离线引擎AiSound5.0,主要用于汽车导航用途.科大讯飞还提供 了AiT ...

  9. 问题-WIN7 ..\Bin\InitCC32.exe".进程无法访问(拒绝访问)

    问题现象: 问题原因:是InitCC32.exe没有权限. 问题处理:在DELPHI7的安装目录里设置用户权限,加入EVE... 这个用户.

  10. Linux Pmap 命令:查看进程用了多少内存

    Pmap 提供了进程的内存映射,pmap命令用于显示一个或多个进程的内存状态.其报告进程的地址空间和内存状态信息.Pmap实际上是一个Sun OS上的命令,linux仅支持其有限的功能.但是它还是对查 ...