Android实现炫酷的网络直播弹幕功能

现在网络直播越来越火,网络主播也逐渐成为一种新兴职业,对于网络直播,弹幕功能是必须要有的,如下图:

首先来分析一下,这个弹幕功能是怎么实现的,首先在最下面肯定是一个游戏界面View,然后游戏界面上有弹幕View,弹幕的View必须要做成完全透明的,这样即使覆盖在游戏界面的上方也不会影响到游戏的正常观看,只有当有人发弹幕消息时,再将消息绘制到弹幕的View上面就可以了,下方肯定还有有操作界面View,可以让用户来发弹幕和送礼物的功能,原理示意图如下所示:

参照原理图,下面一步一步来实现这个功能。

实现视频的播放

activity_main.xml

<RelativeLayout
  xmlns:android="http://schemas.android.com/apk/res/android"
  android:id="@+id/activity_main"
  android:layout_width="match_parent"
  android:layout_height="match_parent"
  android:background="#000"> 

  <VideoView
    android:id="@+id/video_view"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:layout_centerInParent="true"/>
</RelativeLayout>

MainActivity.java

package com.jackie.bombscreen; 

import android.os.Build;
import android.os.Bundle;
import android.os.Environment;
import android.support.v7.app.AppCompatActivity;
import android.view.View;
import android.widget.VideoView; 

public class MainActivity extends AppCompatActivity {
  @Override
  protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);
    VideoView videoView = (VideoView) findViewById(R.id.video_view);
    videoView.setVideoPath(Environment.getExternalStorageDirectory() + "/xiaoxingyun.mp4");
    videoView.start();
  } 

  @Override
  public void onWindowFocusChanged(boolean hasFocus) {
    super.onWindowFocusChanged(hasFocus);
    if (hasFocus && Build.VERSION.SDK_INT >= 19) {
      View decorView = getWindow().getDecorView();
      decorView.setSystemUiVisibility(
          View.SYSTEM_UI_FLAG_LAYOUT_STABLE
              | View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION
              | View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN
              | View.SYSTEM_UI_FLAG_HIDE_NAVIGATION
              | View.SYSTEM_UI_FLAG_FULLSCREEN
              | View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY);
    }
  }
}

最后别忘了设置AndroidMainfest.xml

效果如下:

实现弹幕的效果

接下来我们开始实现弹幕效果。弹幕其实也就是一个自定义的View,它的上面可以显示类似于跑马灯的文字效果。观众们发表的评论都会在弹幕上显示出来,但又会很快地移出屏幕,既可以起到互动的作用,同时又不会影响视频的正常观看。

我们可以自己来编写这样的一个自定义View,当然也可以直接使用网上现成的开源项目。那么为了能够简单快速地实现弹幕效果,这里我就准备直接使用由哔哩哔哩开源的弹幕效果库DanmakuFlameMaster。

DanmakuFlameMaster库的项目主页地址是:https://github.com/Bilibili/DanmakuFlameMaster

添加build.gradle依赖

compile 'com.github.ctiao:DanmakuFlameMaster:0.5.3'

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout
  xmlns:android="http://schemas.android.com/apk/res/android"
  android:id="@+id/activity_main"
  android:layout_width="match_parent"
  android:layout_height="match_parent"
  android:background="#000"> 

  <VideoView
    android:id="@+id/video_view"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:layout_centerInParent="true"/> 

  <master.flame.danmaku.ui.widget.DanmakuView
    android:id="@+id/danmaku_view"
    android:layout_width="match_parent"
    android:layout_height="match_parent" />
</RelativeLayout>

修改MainActivity.java

package com.jackie.bombscreen; 

import android.graphics.Color;
import android.os.Build;
import android.os.Bundle;
import android.os.Environment;
import android.support.v7.app.AppCompatActivity;
import android.view.View;
import android.widget.VideoView; 

import java.util.Random; 

import master.flame.danmaku.controller.DrawHandler;
import master.flame.danmaku.danmaku.model.BaseDanmaku;
import master.flame.danmaku.danmaku.model.DanmakuTimer;
import master.flame.danmaku.danmaku.model.IDanmakus;
import master.flame.danmaku.danmaku.model.android.DanmakuContext;
import master.flame.danmaku.danmaku.model.android.Danmakus;
import master.flame.danmaku.danmaku.parser.BaseDanmakuParser;
import master.flame.danmaku.ui.widget.DanmakuView; 

public class MainActivity extends AppCompatActivity {
  private boolean mIsShowDanmaku;
  private DanmakuView mDanmakuView;
  private DanmakuContext mDanmakuContext; 

  private BaseDanmakuParser parser = new BaseDanmakuParser() {
    @Override
    protected IDanmakus parse() {
      return new Danmakus();
    }
  }; 

  @Override
  protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);
    VideoView videoView = (VideoView) findViewById(R.id.video_view);
    videoView.setVideoPath(Environment.getExternalStorageDirectory() + "/xiaoxingyun.mp4");
    videoView.start(); 

    mDanmakuView = (DanmakuView) findViewById(R.id.danmaku_view);
    mDanmakuView.enableDanmakuDrawingCache(true);
    mDanmakuView.setCallback(new DrawHandler.Callback() {
      @Override
      public void prepared() {
        mIsShowDanmaku = true;
        mDanmakuView.start();
        generateSomeDanmaku();
      } 

      @Override
      public void updateTimer(DanmakuTimer timer) { 

      } 

      @Override
      public void danmakuShown(BaseDanmaku danmaku) { 

      } 

      @Override
      public void drawingFinished() { 

      }
    }); 

    mDanmakuContext = DanmakuContext.create();
    mDanmakuView.prepare(parser, mDanmakuContext);
  } 

  /**
   * 向弹幕View中添加一条弹幕
   * @param content    弹幕的具体内容
   * @param withBorder  弹幕是否有边框
   */
  private void addDanmaku(String content, boolean withBorder) {
    BaseDanmaku danmaku = mDanmakuContext.mDanmakuFactory.createDanmaku(BaseDanmaku.TYPE_SCROLL_RL);
    danmaku.text = content;
    danmaku.padding = 5;
    danmaku.textSize = sp2px(20);
    danmaku.textColor = Color.WHITE;
    danmaku.setTime(mDanmakuView.getCurrentTime());
    if (withBorder) {
      danmaku.borderColor = Color.GREEN;
    }
    mDanmakuView.addDanmaku(danmaku);
  } 

  /**
   * 随机生成一些弹幕内容以供测试
   */
  private void generateSomeDanmaku() {
    new Thread(new Runnable() {
      @Override
      public void run() {
        while(mIsShowDanmaku) {
          int time = new Random().nextInt(300);
          String content = "" + time + time;
          addDanmaku(content, false);
          try {
            Thread.sleep(time);
          } catch (InterruptedException e) {
            e.printStackTrace();
          }
        }
      }
    }).start();
  } 

  /**
   * sp转px的方法。
   */
  public int sp2px(float spValue) {
    final float fontScale = getResources().getDisplayMetrics().scaledDensity;
    return (int) (spValue * fontScale + 0.5f);
  } 

  @Override
  protected void onPause() {
    super.onPause();
    if (mDanmakuView != null && mDanmakuView.isPrepared()) {
      mDanmakuView.pause();
    }
  } 

  @Override
  protected void onResume() {
    super.onResume();
    if (mDanmakuView != null && mDanmakuView.isPrepared() && mDanmakuView.isPaused()) {
      mDanmakuView.resume();
    }
  } 

  @Override
  protected void onDestroy() {
    super.onDestroy();
    mIsShowDanmaku = false;
    if (mDanmakuView != null) {
      mDanmakuView.release();
      mDanmakuView = null;
    }
  } 

  @Override
  public void onWindowFocusChanged(boolean hasFocus) {
    super.onWindowFocusChanged(hasFocus);
    if (hasFocus && Build.VERSION.SDK_INT >= 19) {
      View decorView = getWindow().getDecorView();
      decorView.setSystemUiVisibility(
          View.SYSTEM_UI_FLAG_LAYOUT_STABLE
              | View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION
              | View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN
              | View.SYSTEM_UI_FLAG_HIDE_NAVIGATION
              | View.SYSTEM_UI_FLAG_FULLSCREEN
              | View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY);
    }
  }
}

效果图如下:

加入操作界面

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout
  xmlns:android="http://schemas.android.com/apk/res/android"
  android:id="@+id/activity_main"
  android:layout_width="match_parent"
  android:layout_height="match_parent"
  android:background="#000"> 

  <VideoView
    android:id="@+id/video_view"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:layout_centerInParent="true"/> 

  <master.flame.danmaku.ui.widget.DanmakuView
    android:id="@+id/danmaku_view"
    android:layout_width="match_parent"
    android:layout_height="match_parent" /> 

  <LinearLayout
    android:id="@+id/operation_layout"
    android:layout_width="match_parent"
    android:layout_height="50dp"
    android:layout_alignParentBottom="true"
    android:background="#fff"
    android:visibility="gone"> 

    <EditText
      android:id="@+id/edit_text"
      android:layout_width="0dp"
      android:layout_height="match_parent"
      android:layout_weight="1" /> 

    <Button
      android:id="@+id/send"
      android:layout_width="wrap_content"
      android:layout_height="match_parent"
      android:text="Send" />
  </LinearLayout>
</RelativeLayout>
package com.jackie.bombscreen; 

import android.graphics.Color;
import android.os.Build;
import android.os.Bundle;
import android.os.Environment;
import android.support.v7.app.AppCompatActivity;
import android.text.TextUtils;
import android.view.View;
import android.widget.Button;
import android.widget.EditText;
import android.widget.LinearLayout;
import android.widget.VideoView; 

import java.util.Random; 

import master.flame.danmaku.controller.DrawHandler;
import master.flame.danmaku.danmaku.model.BaseDanmaku;
import master.flame.danmaku.danmaku.model.DanmakuTimer;
import master.flame.danmaku.danmaku.model.IDanmakus;
import master.flame.danmaku.danmaku.model.android.DanmakuContext;
import master.flame.danmaku.danmaku.model.android.Danmakus;
import master.flame.danmaku.danmaku.parser.BaseDanmakuParser;
import master.flame.danmaku.ui.widget.DanmakuView; 

public class MainActivity extends AppCompatActivity {
  private boolean mIsShowDanmaku;
  private DanmakuView mDanmakuView;
  private DanmakuContext mDanmakuContext; 

  private BaseDanmakuParser parser = new BaseDanmakuParser() {
    @Override
    protected IDanmakus parse() {
      return new Danmakus();
    }
  }; 

  @Override
  protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);
    VideoView videoView = (VideoView) findViewById(R.id.video_view);
    videoView.setVideoPath(Environment.getExternalStorageDirectory() + "/xiaoxingyun.mp4");
    videoView.start(); 

    mDanmakuView = (DanmakuView) findViewById(R.id.danmaku_view);
    mDanmakuView.enableDanmakuDrawingCache(true);
    mDanmakuView.setCallback(new DrawHandler.Callback() {
      @Override
      public void prepared() {
        mIsShowDanmaku = true;
        mDanmakuView.start();
        generateSomeDanmaku();
      } 

      @Override
      public void updateTimer(DanmakuTimer timer) { 

      } 

      @Override
      public void danmakuShown(BaseDanmaku danmaku) { 

      } 

      @Override
      public void drawingFinished() { 

      }
    }); 

    mDanmakuContext = DanmakuContext.create();
    mDanmakuView.prepare(parser, mDanmakuContext); 

    final LinearLayout operationLayout = (LinearLayout) findViewById(R.id.operation_layout);
    final Button send = (Button) findViewById(R.id.send);
    final EditText editText = (EditText) findViewById(R.id.edit_text);
    mDanmakuView.setOnClickListener(new View.OnClickListener() {
      @Override
      public void onClick(View view) {
        if (operationLayout.getVisibility() == View.GONE) {
          operationLayout.setVisibility(View.VISIBLE);
        } else {
          operationLayout.setVisibility(View.GONE);
        }
      }
    }); 

    send.setOnClickListener(new View.OnClickListener() {
      @Override
      public void onClick(View view) {
        String content = editText.getText().toString();
        if (!TextUtils.isEmpty(content)) {
          addDanmaku(content, true);
          editText.setText("");
        }
      }
    }); 

    getWindow().getDecorView().setOnSystemUiVisibilityChangeListener (new View.OnSystemUiVisibilityChangeListener() {
      @Override
      public void onSystemUiVisibilityChange(int visibility) {
        if (visibility == View.SYSTEM_UI_FLAG_VISIBLE) {
          onWindowFocusChanged(true);
        }
      }
    });
  } 

  /**
   * 向弹幕View中添加一条弹幕
   * @param content    弹幕的具体内容
   * @param withBorder  弹幕是否有边框
   */
  private void addDanmaku(String content, boolean withBorder) {
    BaseDanmaku danmaku = mDanmakuContext.mDanmakuFactory.createDanmaku(BaseDanmaku.TYPE_SCROLL_RL);
    danmaku.text = content;
    danmaku.padding = 5;
    danmaku.textSize = sp2px(20);
    danmaku.textColor = Color.WHITE;
    danmaku.setTime(mDanmakuView.getCurrentTime());
    if (withBorder) {
      danmaku.borderColor = Color.GREEN;
    }
    mDanmakuView.addDanmaku(danmaku);
  } 

  /**
   * 随机生成一些弹幕内容以供测试
   */
  private void generateSomeDanmaku() {
    new Thread(new Runnable() {
      @Override
      public void run() {
        while(mIsShowDanmaku) {
          int time = new Random().nextInt(300);
          String content = "" + time + time;
          addDanmaku(content, false);
          try {
            Thread.sleep(time);
          } catch (InterruptedException e) {
            e.printStackTrace();
          }
        }
      }
    }).start();
  } 

  /**
   * sp转px的方法。
   */
  public int sp2px(float spValue) {
    final float fontScale = getResources().getDisplayMetrics().scaledDensity;
    return (int) (spValue * fontScale + 0.5f);
  } 

  @Override
  protected void onPause() {
    super.onPause();
    if (mDanmakuView != null && mDanmakuView.isPrepared()) {
      mDanmakuView.pause();
    }
  } 

  @Override
  protected void onResume() {
    super.onResume();
    if (mDanmakuView != null && mDanmakuView.isPrepared() && mDanmakuView.isPaused()) {
      mDanmakuView.resume();
    }
  } 

  @Override
  protected void onDestroy() {
    super.onDestroy();
    mIsShowDanmaku = false;
    if (mDanmakuView != null) {
      mDanmakuView.release();
      mDanmakuView = null;
    }
  } 

  @Override
  public void onWindowFocusChanged(boolean hasFocus) {
    super.onWindowFocusChanged(hasFocus);
    if (hasFocus && Build.VERSION.SDK_INT >= 19) {
      View decorView = getWindow().getDecorView();
      decorView.setSystemUiVisibility(
          View.SYSTEM_UI_FLAG_LAYOUT_STABLE
              | View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION
              | View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN
              | View.SYSTEM_UI_FLAG_HIDE_NAVIGATION
              | View.SYSTEM_UI_FLAG_FULLSCREEN
              | View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY);
    }
  }
}

效果图如下:

自己发的弹幕有绿色边框,很容易区分。

基本上实现了弹幕的功能,当然,里面的知识点还有很多,这只是最基本的功能。有时间的话,建议学学DanmakuFlameMaster,里面还有很多炫酷的功能。

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持我们。

(0)

相关推荐

  • Android 实现仿网络直播弹幕功能详解及实例

    Android 网络直播弹幕                最近看好多网络电视,播放器及直播都有弹幕功能,自己周末捣鼓下并实现,以下是网上的资料,大家可以看下. 现在网络直播越来越火,网络主播也逐渐成为一种新兴职业,对于网络直播,弹幕功能是必须要有的,如下图: 首先来分析一下,这个弹幕功能是怎么实现的,首先在最下面肯定是一个游戏界面View,然后游戏界面上有弹幕View,弹幕的View必须要做成完全透明的,这样即使覆盖在游戏界面的上方也不会影响到游戏的正常观看,只有当有人发弹幕消息时,再将消息绘

  • Android编程实现简易弹幕效果示例【附demo源码下载】

    本文实例讲述了Android编程实现简易弹幕效果.分享给大家供大家参考,具体如下: 首先上效果图,类似于360检测到骚扰电话页面: 布局很简单,上面是一个RelativeLayout,下面一个Button. 功能: (1)弹幕生成后自动从右侧往左侧滚动(TranslateAnimation),弹幕消失后立刻被移除. (2)弹幕位置随机出现,并且不重复(防止文字重叠). (3)字体大小在一定范围内随机改变,字体颜色也可以设置. (4)自定义先减速,后加速的Interpolator,弹幕加速进入.减

  • Android EasyBarrage实现轻量级弹幕效果

    本文介绍了Android EasyBarrage实现轻量级弹幕效果,分享给大家,具体如下: 概述 EasyBarrage是Android平台的一种轻量级弹幕效果目前支持以下设置: 自定义字体颜色,支持随机颜色: 自定义字体大小,支持随机字体大小: 支持边框显示,用于区分自己的弹幕和其他弹幕: 自定义边框颜色: 弹幕数据是否允许重复: 自定义单屏显示的最大弹幕数量: 数据不重叠: 支持动态添加弹幕: 不依赖VideoView,数据自动循环显示. github:https://github.com/

  • Android实现自定义的弹幕效果

    一.效果图 先来看看效果图吧~~ 二.实现原理方案 1.自定义ViewGroup-XCDanmuView,继承RelativeLayout来实现,当然也可以继承其他三大布局类哈 2.初始化若干个TextView(弹幕的item View,这里以TextView 为例,当然也可以其他了~),然后通过addView添加到自定义View中 3.通过addView添加到XCDanmuView中,位置在坐标,为了实现 从屏幕外移动进来的效果 我们还需要修改添加进来TextView的位置,以从右向左移动方向

  • Android仿斗鱼直播的弹幕效果

    记得之前有位朋友在我的公众号里问过我,像直播的那种弹幕功能该如何实现?如今直播行业确实是非常火爆啊,大大小小的公司都要涉足一下直播的领域,用斗鱼的话来讲,现在就是千播之战.而弹幕则无疑是直播功能当中最为重要的一个功能之一,那么今天,我就带着大家一起来实现一个简单的Android端弹幕效果. 分析 首先我们来看一下斗鱼上的弹幕效果,如下图所示: 这是一个Dota2游戏直播的界面,我们可以看到,在游戏界面的上方有很多的弹幕,看直播的观众们就是在这里进行讨论的. 那么这样的一个界面该如何实现呢?其实并

  • 实例解析如何在Android应用中实现弹幕动画效果

    在B站或者其他视频网站看视频时,常常会打开弹幕效果,边看节目边看大家的吐槽.弹幕看起来很有意思,今天我们就来实现一个简单的弹幕效果. 从直观上,弹幕效果就是在一个ViewGroup上增加一些View,然后让这些View移动起来.所以,整体的实现思路大概是这样的: 1.定义一个RelativeLayout,在里面动态添加TextView. 2.这些TextView的字体大小.颜色.移动速度.初始位置都是随机的. 3.将TextView添加到RelativeLayout的右边缘,每隔一段时间添加一个

  • Android弹幕框架 黑暗火焰使基本使用方法

    今天我将分享由BiliBili开源的Android弹幕框架(DanmakuFlameMaster)的学习经验. 我是将整个框架以model的形式引入项目中的,这样更方便的观察源码.也可以通过依赖的方式注入进来 dependencies { compile 'com.github.ctiao:DanmakuFlameMaster:0.5.3' } 先放一下我要做成的效果图: 页面分析 从上图来看,整个UI分成了三层.最下面是视频层,中间是弹幕层,顶层是控制层.现在市场上主流的视频直播软件大多都是这

  • Android自制精彩弹幕效果

    好久没有写过文章,最近发现直播特别的火,很多app都集成了直播的功能,发现有些直播是带有弹幕的,效果还不错,今天心血来潮,特地写了篇制作弹幕的文章. 今天要实现的效果如下: 1.弹幕垂直方向固定 2.弹幕垂直方向随机 上面效果图中白色的背景就是弹幕本身,是一个自定义的FrameLayout,我这里是为了更好的展示弹幕的位置才设置成了白色,当然如果是叠加在VideoView上的话,就需要设置成透明色了. 制作弹幕需要考虑以下几点问题: 1.弹幕的大小可以随意调整 2.弹幕内移动的item(或者称字

  • 很棒的Android弹幕效果实例

    很多项目需要用到弹幕效果,尤其是在播放视频的时候需要一起显示别人发的弹幕,也包括自己的发的. 今天就试着写了一下这个效果. 思路就是将从右往左的动画效果,字体内容,字体大小,弹幕平移速度等属性一起与TextView封装成BarrageItem,并将控制效果与BarrageItem绑定在BarrageView进行显示.思路还是比较简单的.这里没有考虑到带有表情的弹幕,我会持续更新的. 先看效果: 项目目录结构: 接下来定义Barrageitem.class : 这个类就将TextView与从右往左

  • Android实现炫酷的网络直播弹幕功能

    现在网络直播越来越火,网络主播也逐渐成为一种新兴职业,对于网络直播,弹幕功能是必须要有的,如下图: 首先来分析一下,这个弹幕功能是怎么实现的,首先在最下面肯定是一个游戏界面View,然后游戏界面上有弹幕View,弹幕的View必须要做成完全透明的,这样即使覆盖在游戏界面的上方也不会影响到游戏的正常观看,只有当有人发弹幕消息时,再将消息绘制到弹幕的View上面就可以了,下方肯定还有有操作界面View,可以让用户来发弹幕和送礼物的功能,原理示意图如下所示: 参照原理图,下面一步一步来实现这个功能.

  • Android打造炫酷的电影票在线选座app在线选座功能

    不知道大家有没有用过,淘宝电影客户端(淘票票)买过电影票,纵观各类在线选座app的在线选座功能 淘宝在线选座功能用户体验最好,用起来最顺手,夸张点说已经到了炉火纯青的地步,下面我们看一下效果: 效果分析: 整个控件分成几个部分,座位图区域.座位缩略图区域.行号区域.屏幕区域 1.座位图可以自由的移动缩放,放大缩小移动后会自动回弹到合适的位置,选中座位会自动放大到合适比例. 2.行号部分跟着座位图缩放以及上下移动,屏幕区域跟着座位图左右移动缩放. 3.当手指按下的时候会出现缩略图,缩略图上有个红色

  • 教你制作Android中炫酷的ViewPagerIndicator(不仅仿MIUI)

    1.概述 今天给大家带来一个ViewPagerIndicator的制作,相信大家在做tabIndicator的时候,大多数人都用过TabPageIndicator,并且很多知名APP都使用过这个开源的指示器.大家有没有想过如何自己去实现这样的一个指示器,并且代码会有多复杂呢~~~ 今天,我就带领大家来从无到有的实现这样一个指示器,当然了,不准备一模一样,搞得没有创新似的,再看标题,跟MIUI相关,所以我们准备做一个特性与TabPageIndicator一致的,但是样子和MIUI的Tab一样的~~

  • Android打造炫酷进度条效果

    本文实例为大家分享了Android炫酷进度条效果的具体代码,供大家参考,具体内容如下 学习:视频地址 HorizontalProgressbarWithProgress的代码 import android.content.Context; import android.content.res.TypedArray; import android.graphics.Canvas; import android.graphics.Paint; import android.os.Build; imp

  • 代码详解iOS视频直播弹幕功能

    本篇内容通过步骤详细给大家讲解了iOS视频直播弹幕的原理以及实现代码分析,以下就是全部内容: 1.弹幕的实现性分析 首先,从视觉上明确当前弹幕所具有的功能 从屏幕右侧滑入左侧,直至完全消失 不管是长的弹幕,还是短的弹幕,速度一致(可能有的需求是依据弹幕长度,调整速度) 有弹幕轨道,不是随机产生的弹幕 弹幕不会进行重叠 接下来从功能角度思考需要做什么 重用机制,类似tableView有一个重用池,每个弹幕就是一个cell,当有弹幕发送的时候,如果当前的重用池没有控件,则创建一个新的控件,如果重用池

  • Android绘制炫酷引导界面

    一个超炫的引导界面,分享给大家 代码: MainActivity.java package com.bzu.gxs.webview1; import android.app.Activity; import android.os.Build; import android.support.v7.app.AppCompatActivity; import android.os.Bundle; import android.view.KeyEvent; import android.view.Men

  • Android实现炫酷轮播图效果

    轮播图的实现有很多种方式,早先我在网上看了下别人写的轮播图,感觉都比较的墨守成规,有的还有可能加载不了网络图片.所以我在这里自己重新写了下轮播图 ,方便日后的项目使用. 在下面的代码中,我也用volley封装了网络请求框架,异步加载网络图片,也可以给大家参考,非常实用. 效果图:这只是其中的一种效果 底层封装的我在下面会一一展示,先看下在MainActivity中怎样调取这个轮播控件 package com.wujie.advertisment.activity; import android.

  • Android绘制炫酷的引导界面

    先看一下我们要开发的界面(三张图片,滑到最后一个会出现开始体验的Button,下面的小红点会跟着一起滑动): 首先看一下布局文件: <?xml version="1.0" encoding="utf-8"?> <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.and

  • Android实现炫酷的CheckBox效果

    首先贴出实现的效果图: gif的效果可能有点过快,在真机上运行的效果会更好一些.我们主要的思路就是利用属性动画来动态地画出选中状态以及对勾的绘制过程.看到上面的效果图,相信大家都迫不及待地要跃跃欲试了,那就让我们开始吧. 自定义View的第一步:自定义属性. <?xml version="1.0" encoding="utf-8"?> <resources> <declare-styleable name="SmoothChe

随机推荐