介绍
此文章仅为自我做笔记用,各位大佬请移步😂!
此自定义弹幕库是很久之前在做直播时开发的需求。因其功能强大代码简洁。所以一直很喜欢这个功能。多年之后提及相关的东西仍觉很不错。所以在此记录分享一下。
代码
RoomDanmakuView.java
package com.wobo.live.room.danmaku;
import android.content.Context;
import android.util.AttributeSet;
import android.view.View;
import com.wobo.live.room.danmakulib.DanmakuView;
import java.util.ArrayList;
import java.util.List;
/**
* Created by zhou on 2016/5/31.
*/
public class RoomDanmakuView extends DanmakuView {
public List<DanmakuBean> mDanmakuList = new ArrayList<>();
public RoomDanmakuView(Context context) {
super(context);
}
public RoomDanmakuView(Context context, AttributeSet attrs) {
super(context, attrs);
}
@Override
public List getDanmakuCacheList() {
return mDanmakuList;
}
@Override
public View getChildView(int pos) {
return new DanmakuChildView(getContext(),mDanmakuList.get(pos));
}
}
DanmakuChildView.java
package com.wobo.live.room.danmaku;
import android.content.Context;
import android.util.AttributeSet;
import android.view.LayoutInflater;
import android.view.View;
import android.widget.ImageView;
import android.widget.LinearLayout;
import android.widget.TextView;
import com.wobo.live.app.utils.WboImageUrlUtils;
import com.wobo.live.expressing.SplitEmojiContentUtils;
import com.xiu8.android.activity.R;
/**
* Created by zhou on 2016/5/31.
*/
public class DanmakuChildView extends LinearLayout{
private DanmakuBean mDanmaku;
public DanmakuChildView(Context context) {
super(context);
initView();
}
public DanmakuChildView(Context context, AttributeSet attrs) {
super(context, attrs);
initView();
}
public DanmakuChildView(Context context,DanmakuBean danmaku) {
super(context);
mDanmaku = danmaku;
initView();
}
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
super.onMeasure(MeasureSpec.makeMeasureSpec(MeasureSpec.getSize(widthMeasureSpec),MeasureSpec.UNSPECIFIED), heightMeasureSpec);
}
private void initView() {
View v = LayoutInflater.from(getContext()).inflate(R.layout.view_danmaku_child, this, true);
ImageView nobleIcon = (ImageView)v.findViewById(R.id.nobleIcon);
TextView danmakuMsg = (TextView)v.findViewById(R.id.danmaku_msg);
SplitEmojiContentUtils.setEmoji(getContext(),danmakuMsg,mDanmaku.getNickName()+":"+mDanmaku.msg);
if(mDanmaku.getUser().getNobleLevel()>0){
nobleIcon.setVisibility(View.VISIBLE);
nobleIcon.setImageResource(WboImageUrlUtils.getImage("noble_",mDanmaku.getUser().getNobleLevel()+""));
}else{
nobleIcon.setVisibility(View.GONE);
}
if(mDanmaku.getIsNoble()==1){
v.setBackgroundResource(WboImageUrlUtils.getImage("noble_danmu_bg_",mDanmaku.getUser().getNobleLevel()+""));
}else{
v.setBackgroundResource(R.drawable.noble_danmu_bg_1);
}
}
}
DanmakuBean.java
package com.wobo.live.room.danmaku;
import com.wobo.live.app.WboBean;
import com.wobo.live.room.userbean.UserRoomInfo;
/**
* Created by zhou on 2016/5/31.
*/
public class DanmakuBean extends WboBean{
private long userId;
private int level;
private String avatar;
public String msg;
private String nickName;
private UserRoomInfo user;
private int playFlag;
private int isNoble;//是否是贵族弹幕 1是 0不是
public int getIsNoble() {
// return new Random().nextInt(2);
return isNoble;
}
public int getPlayFlag() {
return playFlag;
}
public void setPlayFlag(int playFlag) {
this.playFlag = playFlag;
}
public long getUserId() {
return userId;
}
public void setUserId(long userId) {
this.userId = userId;
}
public int getUserlevel() {
return user.getUserLevel();
}
public String getAvatar() {
return avatar;
}
public void setAvatar(String avater) {
this.avatar = avater;
}
public String getMsg() {
return msg;
}
public void setMsg(String msg) {
this.msg = msg;
}
public String getNickName() {
return nickName;
}
public void setNickName(String nickName) {
this.nickName = nickName;
}
public DanmakuBean(long userId, int consumeLevel, String avatar, String msg, String nickName) {
this.userId = userId;
this.level = consumeLevel;
this.avatar = avatar;
this.msg = msg;
this.nickName = nickName;
}
public UserRoomInfo getUser() {
return user;
}
public void setUser(UserRoomInfo user) {
this.user = user;
}
public int getLevel()
{
return level;
}
}
DanmakuContainer.java
package com.wobo.live.room.danmakulib;
import android.content.Context;
import android.util.AttributeSet;
import android.view.LayoutInflater;
import android.view.View;
import android.view.animation.Animation;
import android.view.animation.LinearInterpolator;
import android.view.animation.TranslateAnimation;
import android.widget.RelativeLayout;
import com.android.frame.utils.VLDensityUtils;
import com.xiu8.android.activity.R;
import java.util.Timer;
import java.util.TimerTask;
/**
* Created by zhou on 2016/5/31.
*/
public class DanmakuContainer extends RelativeLayout{
private long tempTime = 0;
private int ALLTIME = 5000;
private final int SPACE_TIEM = 1200;
private int safeTime = 0;
private IShowNextDanmakuListener showNext;
public DanmakuContainer(Context context) {
super(context);
initView();
}
public DanmakuContainer(Context context, AttributeSet attrs) {
super(context, attrs);
initView();
}
private void initView() {
View v = LayoutInflater.from(getContext()).inflate(R.layout.view_danmaku_container, this, true);
}
public boolean isCanShow(View danmakuChildView){
if(danmakuChildView==null){//如果送过来的view为空则证明外面有处理不了的view类型,所以直接返回true,让上层移除当前bean
return true;
}
int w = MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED);
int h = MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED);
danmakuChildView.measure(w, h);
int measuredWidth = danmakuChildView.getMeasuredWidth();
// System.out.println("(ALLTIME-(System.currentTimeMillis()-tempTime)+SPACE_TIEM="+(ALLTIME-(System.currentTimeMillis()-tempTime)+SPACE_TIEM)+"----"+"VLDensityUtils.getScreenWidth()*ALLTIME/(VLDensityUtils.getScreenWidth()+measuredWidth))"+VLDensityUtils.getScreenWidth()*ALLTIME/(VLDensityUtils.getScreenWidth()+measuredWidth)+"System.currentTimeMillis()-tempTime"+(System.currentTimeMillis()-tempTime)+"safeTime"+safeTime);
// System.out.println("System.currentTimeMillis()"+System.currentTimeMillis()+" tempTime"+tempTime);
// System.out.println("tempTime"+tempTime+" safeTime="+safeTime);
if((ALLTIME-(System.currentTimeMillis())+SPACE_TIEM<VLDensityUtils.getScreenWidth()*ALLTIME/(VLDensityUtils.getScreenWidth()+measuredWidth))&&(System.currentTimeMillis()-tempTime>safeTime)){
//剩余时间加安全时间 需要小于 第二个view 运行到x为0时的时间 2 当前已启动时间 大于安全时间,这两个条件
//可以处理 先显示 然后 return true
tempTime = System.currentTimeMillis();
safeTime = measuredWidth*ALLTIME/(measuredWidth+VLDensityUtils.getScreenWidth());
showDanmaku(danmakuChildView,measuredWidth,safeTime);
// System.out.println("reutrn true");
return true;
}else{
//不可处理return false;
// System.out.println("reutrn false");
return false;
}
}
Timer timer = new Timer();
public void showDanmaku(final View danmakuChildView, int measuredWidth, final int safeTime){
TranslateAnimation animation = new TranslateAnimation(VLDensityUtils.getScreenWidth(),-measuredWidth,0,0);
animation.setAnimationListener(new Animation.AnimationListener() {
@Override
public void onAnimationStart(Animation animation) {
timer.schedule(new TimerTask(){
@Override
public void run() {
if(showNext!=null){
post(new Runnable() {
@Override
public void run() {
showNext.showNextDanmaku();
}
});
}
}
} ,safeTime+SPACE_TIEM);
}
@Override
public void onAnimationEnd(Animation animation) {
removeView(danmakuChildView);
// WboApplication.instance().broadcastMessage(MessageIDs.MESSAGEID_FC_DANMAKU_GET_LOCAL, null, null);
}
@Override
public void onAnimationRepeat(Animation animation) {
}
});
animation.setInterpolator(new LinearInterpolator());
animation.setDuration(ALLTIME);
danmakuChildView.startAnimation(animation);
addView(danmakuChildView);
}
public void setShowNext(IShowNextDanmakuListener showNext) {
this.showNext = showNext;
}
@Override
protected void onDetachedFromWindow() {
super.onDetachedFromWindow();
timer.cancel();
}
}
IDanmakuView.java
package com.wobo.live.room.danmakulib;
import java.util.List;
/**
* Created by zhou on 2016/5/31.
*/
public interface IDanmakuView {
List getDanmakuCacheList();
boolean isAddDanmakuSuccess(int pos);
}
DanmakuView.java
package com.wobo.live.room.danmakulib;
import android.content.Context;
import android.util.AttributeSet;
import android.view.LayoutInflater;
import android.view.View;
import android.widget.LinearLayout;
import com.xiu8.android.activity.R;
import java.util.List;
/**
* Created by zhou on 2016/5/31.
*/
public abstract class DanmakuView extends LinearLayout implements IDanmakuView {
private DanmakuContainer firstView;
public DanmakuView(Context context) {
super(context);
initView();
}
public DanmakuView(Context context, AttributeSet attrs) {
super(context, attrs);
initView();
}
private void initView() {
View v = LayoutInflater.from(getContext()).inflate(R.layout.view_danmaku, this, true);
firstView = (DanmakuContainer)v.findViewById(R.id.first_view);
firstView.setShowNext(mShowNextListener);
}
@Override
public synchronized boolean isAddDanmakuSuccess(int pos){
if(getDanmakuCacheList().get(pos)==null){
return false;
}
if(firstView.isCanShow(getChildView(pos))){
return true;
}
return false;
}
public abstract List getDanmakuCacheList();
IShowNextDanmakuListener mShowNextListener = new IShowNextDanmakuListener() {
@Override
public void showNextDanmaku() {
if (getDanmakuCacheList().size()>0 && isAddDanmakuSuccess(0)) {
getDanmakuCacheList().remove(0);
}
}
};
public abstract View getChildView(int t);
}
IShowNextDanmakuListener.java
package com.wobo.live.room.danmakulib;
/**
* Created by zhou on 2017/2/15.
*/
public interface IShowNextDanmakuListener {
void showNextDanmaku();
}