弹幕(一)自定义无法暂停
根据时间戳和播放器同步弹幕数据
/**
* 一个简化版的DanmakuViewPool
*/
public class CachedDanmakuViewPool implements Pool<DanmakuView> {
private static final String TAG = "CachedDanmakuViewPool";
/**
* 缓存DanmakuView队列。显示已经完毕的DanmakuView会被添加到缓存中进行复用。
* 在一定的时间{@link CachedDanmakuViewPool#mKeepAliveTime}过后,没有被访问到的DanmakuView会被回收。
*/
private LinkedList<DanmakuViewWithExpireTime> mCache = new LinkedList<>();
/**
* 缓存存活时间
*/
private long mKeepAliveTime;
/**
* 定时清理缓存
*/
private ScheduledExecutorService mChecker = Executors.newSingleThreadScheduledExecutor();
/**
* 创建新DanmakuView的Creator
*/
private ViewCreator<DanmakuView> mCreator;
/**
* 最大DanmakuView数量。
* 这个数量包含了正在显示的DanmakuView和已经显示完毕进入缓存等待复用的DanmakuView之和。
*/
private int mMaxSize;
/**
* 正在显示的弹幕数量。
*/
private int mInUseSize;
/**
* @param creator 生成一个DanmakuView
*/
CachedDanmakuViewPool(long keepAliveTime, int maxSize, ViewCreator<DanmakuView> creator) {
mKeepAliveTime = keepAliveTime;
mMaxSize = maxSize;
mCreator = creator;
mInUseSize = 0;
scheduleCheckUnusedViews();
}
/**
* 每隔一秒检查并清理掉空闲队列中超过一定时间没有被使用的DanmakuView
*/
private void scheduleCheckUnusedViews() {
mChecker.scheduleWithFixedDelay(() -> {
// EasyL.v(TAG, "scheduleCheckUnusedViews: mInUseSize=" + mInUseSize + ", mCacheSize=" + mCache.size());
long current = System.currentTimeMillis();
while (!mCache.isEmpty()) {
DanmakuViewWithExpireTime first = mCache.getFirst();
if (current > first.expireTime) {
mCache.remove(first);
} else {
break;
}
}
}, 1000, 1000, TimeUnit.MILLISECONDS);
}
@Override
public DanmakuView get() {
DanmakuView view;
if (mCache.isEmpty()) { // 缓存中没有View
if (mInUseSize >= mMaxSize) {
return null;
}
view = mCreator.create();
} else { // 有可用的缓存,从缓存中取
view = mCache.poll().danmakuView;
}
view.addOnExitListener(v -> {
long expire = System.currentTimeMillis() + mKeepAliveTime;
v.restore();
DanmakuViewWithExpireTime item = new DanmakuViewWithExpireTime();
item.danmakuView = v;
item.expireTime = expire;
mCache.offer(item);
mInUseSize--;
});
mInUseSize++;
return view;
}
@Override
public void release() {
mCache.clear();
}
/**
* @return 使用中的DanmakuView和缓存中的DanmakuView数量之和
*/
@Override
public int count() {
return mCache.size() + mInUseSize;
}
@Override
public void setMaxSize(int max) {
mMaxSize = max;
}
/**
* 一个包裹类,保存一个DanmakuView和它的过期时间。
*/
private class DanmakuViewWithExpireTime {
private DanmakuView danmakuView; // 缓存的DanmakuView
private long expireTime; // 超过这个时间没有被访问的缓存将被丢弃
}
public interface ViewCreator<T> {
T create();
}
}
public class Danmaku {
public static final String COLOR_WHITE = "#ffffffff";
public static final String COLOR_FFD662 = "#FFD662";
public static final String COLOR_RED = "#ffff0000";
public static final String COLOR_GREEN = "#ff00ff00";
public static final String COLOR_BLUE = "#ff0000ff";
public static final String COLOR_YELLOW = "#ffffff00";
public static final String COLOR_PURPLE = "#ffff00ff";
public static final int DEFAULT_TEXT_SIZE = 24;
public String text;// 文字
public int size = DEFAULT_TEXT_SIZE;// 字号
public Mode mode = Mode.scroll;// 模式:滚动、顶部、底部
public String color = COLOR_WHITE;// 默认白色
public String borderColor = "";// 默认无边框
public enum Mode {
scroll, top, bottom
}
public Danmaku() {
}
public Danmaku(String text, int textSize, Mode mode, String color,String borderColor) {
this.text = text;
this.size = textSize;
this.mode = mode;
this.color = color;
if (!TextUtils.isEmpty(borderColor)) {
this.borderColor = borderColor;
}
}
@Override
public String toString() {
return "Danmaku{" +
"text='" + text + '\'' +
", size=" + size +
", mode=" + mode +
", color='" + color + '\'' +
", borderColor='" + borderColor + '\'' +
'}';
}
}
/**
* 用法示例:
* DanmakuManager dm = DanmakuManager.getInstance();
* dm.init(getContext());
* dm.show(new Danmaku("test"));
* <p>
* Created by LittleFogCat.
*/
@SuppressWarnings("unused")
public class DanmakuManager {
private static final String TAG = DanmakuManager.class.getSimpleName();
private static final int RESULT_OK = 0;
private static final int RESULT_NULL_ROOT_VIEW = 1;
private static final int RESULT_FULL_POOL = 2;
private static final int TOO_MANY_DANMAKU = 2;
private static DanmakuManager sInstance;
/**
* 弹幕容器
*/
WeakReference<FrameLayout> mDanmakuContainer;
/**
* 弹幕池
*/
private Pool<DanmakuView> mDanmakuViewPool;
private Config mConfig;
private DanmakuPositionCalculator mPositionCal;
private Context context;
private FrameLayout container;
private DanmakuManager() {
}
public static DanmakuManager getInstance() {
if (sInstance == null) {
sInstance = new DanmakuManager();
}
return sInstance;
}
/**
* 初始化。在使用之前必须调用该方法。
*/
public void init(Context context, FrameLayout container) {
this.context = context;
this.container = container;
if (mDanmakuViewPool == null) {
mDanmakuViewPool = new CachedDanmakuViewPool(
60000, // 缓存存活时间:60秒
200, // 最大弹幕数:100
() -> DanmakuViewFactory.createDanmakuView(context, container));
}
setDanmakuContainer(container);
ScreenUtil.init(context);
mConfig = new Config();
mPositionCal = new DanmakuPositionCalculator(this);
}
public Config getConfig() {
if (mConfig == null) {
mConfig = new Config();
}
return mConfig;
}
private DanmakuPositionCalculator getPositionCalculator() {
if (mPositionCal == null) {
mPositionCal = new DanmakuPositionCalculator(this);
}
return mPositionCal;
}
public void setDanmakuViewPool(Pool<DanmakuView> pool) {
if (mDanmakuViewPool != null) {
mDanmakuViewPool.release();
}
mDanmakuViewPool = pool;
}
public void clearDmAllMessage() {
if (mDanmakuViewPool != null) {
mDanmakuViewPool.release();
}
}
/**
* 设置允许同时出现最多的弹幕数,如果屏幕上显示的弹幕数超过该数量,那么新出现的弹幕将被丢弃,
* 直到有旧的弹幕消失。
*
* @param max 同时出现的最多弹幕数,-1无限制
*/
public void setMaxDanmakuSize(int max) {
if (mDanmakuViewPool == null) {
return;
}
mDanmakuViewPool.setMaxSize(max);
}
/**
* 设置弹幕的容器,所有的弹幕都在这里面显示
*/
public void setDanmakuContainer(final FrameLayout root) {
if (root == null) {
// throw new NullPointerException("Danmaku container cannot be null!");
return;
}
mDanmakuContainer = new WeakReference<>(root);
}
/**
* 发送一条弹幕
*/
public int send(Danmaku danmaku) {
if (mDanmakuViewPool == null) {
// throw new NullPointerException("Danmaku view pool is null. Did you call init() first?");
mDanmakuViewPool = new CachedDanmakuViewPool(
60000, // 缓存存活时间:60秒q
200, // 最大弹幕数:100
() -> DanmakuViewFactory.createDanmakuView(context, container));
}
DanmakuView view = mDanmakuViewPool.get();
if (view == null) {
// EasyL.w(TAG, "show: Too many danmaku, discard");
return RESULT_FULL_POOL;
}
if (mDanmakuContainer == null || mDanmakuContainer.get() == null) {
// EasyL.w(TAG, "show: Root view is null.");
return RESULT_NULL_ROOT_VIEW;
}
view.setDanmaku(danmaku);
// 字体大小
int textSize = danmaku.size;
view.setTextSize(TypedValue.COMPLEX_UNIT_PX, textSize);
// 字体边框
view.setBorderColor(danmaku.borderColor);
// 字体颜色
try {
int color = Color.parseColor(danmaku.color);
view.setTextColor(color);
} catch (Exception e) {
e.printStackTrace();
view.setTextColor(Color.WHITE);
}
// 计算弹幕距离顶部的位置
DanmakuPositionCalculator dpc = getPositionCalculator();
int marginTop = dpc.getMarginTop(view);
if (marginTop == -1) {
// 屏幕放不下了
// EasyL.d(TAG, "send: screen is full, too many danmaku [" + danmaku + "]");
return TOO_MANY_DANMAKU;
}
FrameLayout.LayoutParams p = (FrameLayout.LayoutParams) view.getLayoutParams();
if (p == null) {
p = new FrameLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT);
}
p.topMargin = marginTop;
view.setLayoutParams(p);
view.setMinHeight((int) (getConfig().getLineHeight() * 1.35));
view.show(mDanmakuContainer.get(), getDisplayDuration(danmaku));
return RESULT_OK;
}
/**
* @return 返回这个弹幕显示时长
*/
int getDisplayDuration(Danmaku danmaku) {
Config config = getConfig();
int duration;
switch (danmaku.mode) {
case top:
duration = config.getDurationTop();
break;
case bottom:
duration = config.getDurationBottom();
break;
case scroll:
default:
duration = config.getDurationScroll();
break;
}
return duration;
}
/**
* 一些配置
*/
public static class Config {
/**
* 行高,单位px
*/
private int lineHeight;
/**
* 滚动弹幕显示时长
*/
private int durationScroll;
/**
* 顶部弹幕显示时长
*/
private int durationTop;
/**
* 底部弹幕的显示时长
*/
private int durationBottom;
/**
* 滚动弹幕的最大行数
*/
private int maxScrollLine;
public int getLineHeight() {
return lineHeight;
}
public void setLineHeight(int lineHeight) {
this.lineHeight = lineHeight;
}
public int getMaxScrollLine() {
return maxScrollLine;
}
public int getDurationScroll() {
if (durationScroll == 0) {
durationScroll = 10000;
}
return durationScroll;
}
public void setDurationScroll(int durationScroll) {
this.durationScroll = durationScroll;
}
public int getDurationTop() {
if (durationTop == 0) {
durationTop = 5000;
}
return durationTop;
}
public void setDurationTop(int durationTop) {
this.durationTop = durationTop;
}
public int getDurationBottom() {
if (durationBottom == 0) {
durationBottom = 5000;
}
return durationBottom;
}
public void setDurationBottom(int durationBottom) {
this.durationBottom = durationBottom;
}
public int getMaxDanmakuLine() {
if (maxScrollLine == 0) {
maxScrollLine = 12;
}
return maxScrollLine;
}
public void setMaxScrollLine(int maxScrollLine) {
this.maxScrollLine = maxScrollLine;
}
}
}
/**
* 用于计算弹幕位置,来保证弹幕不重叠又不浪费空间。
*/
class DanmakuPositionCalculator {
private static final String TAG = "DanPositionCalculator";
private DanmakuManager mDanmakuManager;
private List<DanmakuView> mLastDanmakus = new ArrayList<>();// 保存每一行最后一个弹幕消失的时间
private boolean[] mTops;
private boolean[] mBottoms;
DanmakuPositionCalculator(DanmakuManager danmakuManager) {
mDanmakuManager = danmakuManager;
int maxLine = danmakuManager.getConfig().getMaxDanmakuLine();
mTops = new boolean[maxLine];
mBottoms = new boolean[maxLine];
}
private int getLineHeightWithPadding() {
return (int) (1.35f * mDanmakuManager.getConfig().getLineHeight());
}
int getMarginTop(DanmakuView view) {
switch (view.getDanmaku().mode) {
case scroll:
return getScrollY(view);
case top:
return getTopY(view);
case bottom:
return getBottomY(view);
}
return -1;
}
private int getScrollY(DanmakuView view) {
if (mLastDanmakus.size() == 0) {
mLastDanmakus.add(view);
return 0;
}
int i;
for (i = 0; i < mLastDanmakus.size(); i++) {
DanmakuView last = mLastDanmakus.get(i);
int timeDisappear = calTimeDisappear(last); // 最后一条弹幕还需多久消失
int timeArrive = calTimeArrive(view); // 这条弹幕需要多久到达屏幕边缘
boolean isFullyShown = isFullyShown(last);
// EasyL.d(TAG, "getScrollY: 行: " + i + ", 消失时间: " + timeDisappear + ", 到达时间: " + timeArrive + ", 行高: " + lineHeight);
if (timeDisappear <= timeArrive && isFullyShown) {
// 如果最后一个弹幕在这个弹幕到达之前消失,并且最后一个字已经显示完毕,
// 那么新的弹幕就可以在这一行显示
mLastDanmakus.set(i, view);
return i * getLineHeightWithPadding();
}
}
int maxLine = mDanmakuManager.getConfig().getMaxDanmakuLine();
if (maxLine == 0 || i < maxLine) {
mLastDanmakus.add(view);
return i * getLineHeightWithPadding();
}
return -1;
}
private int getTopY(DanmakuView view) {
for (int i = 0; i < mTops.length; i++) {
boolean isShowing = mTops[i];
if (!isShowing) {
final int finalI = i;
mTops[finalI] = true;
view.addOnExitListener(view1 -> mTops[finalI] = false);
return i * getLineHeightWithPadding();
}
}
return -1;
}
private int getBottomY(DanmakuView view) {
for (int i = 0; i < mBottoms.length; i++) {
boolean isShowing = mBottoms[i];
if (!isShowing) {
final int finalI = i;
mBottoms[finalI] = true;
view.addOnExitListener(view1 -> mBottoms[finalI] = false);
return getParentHeight() - (i + 1) * getLineHeightWithPadding();
}
}
return -1;
}
/**
* 这条弹幕是否已经全部出来了。如果没有的话,
* 后面的弹幕不能出来,否则就重叠了。
*/
private boolean isFullyShown(DanmakuView view) {
if (view == null) {
return true;
}
int scrollX = view.getScrollX();
int textLength = view.getTextLength();
return textLength - scrollX < getParentWidth();
}
/**
* 这条弹幕还有多少毫秒彻底消失。
*/
private int calTimeDisappear(DanmakuView view) {
if (view == null) {
return 0;
}
float speed = calSpeed(view);
int scrollX = view.getScrollX();
int textLength = view.getTextLength();
int wayToGo = textLength - scrollX;
return (int) (wayToGo / speed);
}
/**
* 这条弹幕还要多少毫秒抵达屏幕边缘。
*/
private int calTimeArrive(DanmakuView view) {
float speed = calSpeed(view);
int wayToGo = getParentWidth();
return (int) (wayToGo / speed);
}
/**
* 这条弹幕的速度。单位:px/ms
*/
private float calSpeed(DanmakuView view) {
int textLength = view.getTextLength();
int width = getParentWidth();
float s = textLength + width + 0.0f;
int t = mDanmakuManager.getDisplayDuration(view.getDanmaku());
return s / t;
}
private int getParentHeight() {
ViewGroup parent = mDanmakuManager.mDanmakuContainer.get();
if (parent == null || parent.getHeight() == 0) {
return 1080;
}
return parent.getHeight();
}
private int getParentWidth() {
ViewGroup parent = mDanmakuManager.mDanmakuContainer.get();
if (parent == null || parent.getWidth() == 0) {
return 1920;
}
return parent.getWidth();
}
}
/**
* DanmakuView的基类,继承自TextView,一个弹幕对应一个DanmakuView。
* 这里实现了一些通用的功能。
* <p>
* Created by LittleFogCat.
*/
@SuppressWarnings("unused")
public class DanmakuView extends TextViewBorder {
/**
* 弹幕内容
*/
private Danmaku mDanmaku;
/**
* 监听
*/
private ListenerInfo mListenerInfo;
private class ListenerInfo {
private ArrayList<OnEnterListener> mOnEnterListeners;
private List<OnExitListener> mOnExitListener;
}
/**
* 弹幕进场时的监听
*/
public interface OnEnterListener {
void onEnter(DanmakuView view);
}
/**
* 弹幕离场后的监听
*/
public interface OnExitListener {
void onExit(DanmakuView view);
}
/**
* 显示时长 ms
*/
private int mDuration;
public DanmakuView(Context context) {
this(context, null);
}
public DanmakuView(Context context, AttributeSet attrs) {
this(context, attrs, 0);
}
public DanmakuView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
}
/**
* 设置弹幕内容
*/
public void setDanmaku(Danmaku danmaku) {
mDanmaku = danmaku;
setText(danmaku.text);
switch (danmaku.mode) {
case top:
case bottom:
setGravity(Gravity.CENTER);
break;
case scroll:
default:
setGravity(Gravity.START | Gravity.CENTER_VERTICAL);
break;
}
}
public void setBorderColor(String borderColor) {
if (!TextUtils.isEmpty(borderColor)) {
super.setBorderColor(true);
} else {
super.setBorderColor(false);
}
}
public Danmaku getDanmaku() {
return mDanmaku;
}
/**
* 显示弹幕
*/
public void show(final ViewGroup parent, int duration) {
mDuration = duration;
switch (mDanmaku.mode) {
case top:
case bottom:
showFixedDanmaku(parent, duration);
break;
case scroll:
default:
showScrollDanmaku(parent, duration);
break;
}
if (hasOnEnterListener()) {
for (OnEnterListener listener : getListenerInfo().mOnEnterListeners) {
listener.onEnter(this);
}
}
postDelayed(() -> {
setVisibility(GONE);
if (hasOnExitListener()) {
for (OnExitListener listener : getListenerInfo().mOnExitListener) {
listener.onExit(DanmakuView.this);
}
}
parent.removeView(DanmakuView.this);
}, duration);
}
private void showScrollDanmaku(ViewGroup parent, int duration) {
int screenWidth = ScreenUtil.getScreenWidth();
int textLength = getTextLength();
scrollTo(-screenWidth, 0);
parent.addView(this);
smoothScrollTo(textLength, 0, duration);
}
private void showFixedDanmaku(ViewGroup parent, int duration) {
setGravity(Gravity.CENTER);
parent.addView(this);
}
private ListenerInfo getListenerInfo() {
if (mListenerInfo == null) {
mListenerInfo = new ListenerInfo();
}
return mListenerInfo;
}
public void addOnEnterListener(OnEnterListener l) {
ListenerInfo li = getListenerInfo();
if (li.mOnEnterListeners == null) {
li.mOnEnterListeners = new ArrayList<>();
}
if (!li.mOnEnterListeners.contains(l)) {
li.mOnEnterListeners.add(l);
}
}
public void clearOnEnterListeners() {
ListenerInfo li = getListenerInfo();
if (li.mOnEnterListeners == null || li.mOnEnterListeners.size() == 0) {
return;
}
li.mOnEnterListeners.clear();
}
public void addOnExitListener(OnExitListener l) {
ListenerInfo li = getListenerInfo();
if (li.mOnExitListener == null) {
li.mOnExitListener = new CopyOnWriteArrayList<>();
}
if (!li.mOnExitListener.contains(l)) {
li.mOnExitListener.add(l);
}
}
public void clearOnExitListeners() {
ListenerInfo li = getListenerInfo();
if (li.mOnExitListener == null || li.mOnExitListener.size() == 0) {
return;
}
li.mOnExitListener.clear();
}
public boolean hasOnEnterListener() {
ListenerInfo li = getListenerInfo();
return li.mOnEnterListeners != null && li.mOnEnterListeners.size() != 0;
}
public boolean hasOnExitListener() {
ListenerInfo li = getListenerInfo();
return li.mOnExitListener != null && li.mOnExitListener.size() != 0;
}
public int getTextLength() {
return (int) getPaint().measureText(getText().toString());
}
public int getDuration() {
return mDuration;
}
/**
* 恢复初始状态
*/
public void restore() {
clearOnEnterListeners();
clearOnExitListeners();
setVisibility(VISIBLE);
setScrollX(0);
setScrollY(0);
}
private Scroller mScroller;
public void smoothScrollTo(int x, int y, int duration) {
if (mScroller == null) {
mScroller = new Scroller(getContext(), new LinearInterpolator());
setScroller(mScroller);
}
int sx = getScrollX();
int sy = getScrollY();
mScroller.startScroll(sx, sy, x - sx, y - sy, duration);
}
@Override
public void computeScroll() {
if (mScroller != null && mScroller.computeScrollOffset()) {
// EasyL.v(TAG, "computeScroll: " + mScroller.getCurrX());
scrollTo(mScroller.getCurrX(), mScroller.getCurrY());
postInvalidate();
}
}
void callExitListener() {
for (OnExitListener listener : getListenerInfo().mOnExitListener) {
listener.onExit(this);
}
}
}
class DanmakuViewFactory {
@SuppressLint("InflateParams")
static DanmakuView createDanmakuView(Context context) {
return (DanmakuView) LayoutInflater.from(context)
.inflate(R.layout.danmaku_view, null, false);
}
static DanmakuView createDanmakuView(Context context, ViewGroup parent) {
return (DanmakuView) LayoutInflater.from(context)
.inflate(R.layout.danmaku_view, parent, false);
}
}
public class DanMuView extends FrameLayout {
private FrameLayout container;
private DanmakuManager dm;
private static final int SENDDMLIST = 1001;
// private List<IDanmaku> danmakus = new ArrayList<>();
private long currentTime = 0;
private HashMap<Integer, List<BulletBean.DataBean>> danmaku = new HashMap<>();
public DanMuView(@NonNull Context context) {
this(context, null);
}
public DanMuView(@NonNull Context context, @Nullable AttributeSet attrs) {
this(context, attrs, 0);
}
public DanMuView(@NonNull Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
init(context);
}
public void init(Context context) {
View view = LayoutInflater.from(context).inflate(R.layout.danma_layout, this, false);
addView(view);
container = view.findViewById(R.id.frame_layout);
initDanmu(context);
}
private void initDanmu(Context context) {
// 获得DanmakuManager单例
dm = DanmakuManager.getInstance();
dm.init(context, container);
dm.setMaxDanmakuSize(35); // 设置同屏最大弹幕数
DanmakuManager.Config config = dm.getConfig(); // 弹幕相关设置
config.setDurationScroll(10000); // 设置滚动字幕显示时长,默认10秒
config.setMaxScrollLine(3); // 设置滚动字幕最大行数
config.setLineHeight(ScreenUtil.autoSize(40)); // 设置行高
}
public void setDuration(int duration){
DanmakuManager.Config config = dm.getConfig(); // 弹幕相关设置
config.setDurationScroll(duration); // 设置滚动字幕显示时长,默认10秒
}
/**
* 发送弹幕消息
*
* @param danmaku
*/
public void sendDmMessage(IDanmaku danmaku) {
if (container != null) {
dm.setDanmakuContainer(container);
}
dm.send(danmaku);
}
/**
* 发送弹幕组
*
* @param danmakus
*/
public void sendDmMessage(HashMap<Integer, List<BulletBean.DataBean>> danmakus) {
danmaku.clear();
danmaku.putAll(danmakus);
Log.e("zrq_dm","*" + danmaku.size() + " - " + danmakus.size());
if (container != null) {
dm.setDanmakuContainer(container);
}
}
public void clearDmAllMessage() {
DanmakuManager.getInstance().clearDmAllMessage();
container.removeAllViews();
danmaku.clear();
}
public void release() {
clearDmAllMessage();
}
public void setCurrentTime(String date, long time) {
String[] split = date.split(":");
List<BulletBean.DataBean> dataBeans = danmaku.get(Integer.parseInt(time / 60 / 1000 + ""));
// Log.e("zrq_dm"," -- "+danmaku.toString());
if (dataBeans == null) {
return;
}
// Log.e("zrq_dm","----");
int curTime = Integer.parseInt(split[0]) * 60 * 60 + Integer.parseInt(split[1]) * 60 + Integer.parseInt(split[2]);
for (int i = 0; i < dataBeans.size(); i++) {
BulletBean.DataBean dataBean = dataBeans.get(i);
// if (Integer.parseInt(split[2]) == dataBean.time && Integer.parseInt(split[1]) == dataBean.minute){
if (curTime == dataBean.time) {
sendDmMessage(new IDanmaku(0, dataBeans.get(i).content));
}
}
}
public void setCurrentTime(long time) {
currentTime = time;
//对应的分取对应内的所有数据
List<BulletBean.DataBean> dataBeans = danmaku.get(Integer.parseInt(currentTime / 60 / 1000 + ""));
if (dataBeans == null) {
return;
}
for (int i = 0; i < dataBeans.size(); i++) {
long times = (long) dataBeans.get(i).minute * 1000 * 60 + dataBeans.get(i).time * 1000;
if (currentTime <= times && times <= currentTime + 1000) {
sendDmMessage(new IDanmaku(times, dataBeans.get(i).content));
}
}
// for (int i = 0; i < danmakus.size(); i++) {
// if (currentTime <= danmakus.get(i).time && currentTime + 1000 >= danmakus.get(i).time) {
// sendDmMessage(danmakus.get(i));
// break;
// }
// }
}
}
public class IDanmaku extends Danmaku {
public long time;
public String text;
public int size = Danmaku.DEFAULT_TEXT_SIZE;
public IDanmaku(long time,String text,int textSize) {
super(text,textSize,Mode.scroll,COLOR_WHITE,"");
this.time = time;
this.size = textSize;
}
public IDanmaku(long time,String text,String textColor) {
super(text,50,Mode.scroll,textColor,"");
this.time = time;
this.size = 50;
}
public IDanmaku(long time,String text,String textColor,String borderColor) {
super(text,50,Mode.scroll,textColor,borderColor);
this.time = time;
this.size = 50;
}
public IDanmaku(long time,String text) {
super(text,50,Mode.scroll,COLOR_WHITE,"");
this.time = time;
}
}
public interface Pool<T> {
/**
* 从缓存中获取一个T的实例
*/
T get();
/**
* 释放缓存
*/
void release();
/**
* @return 缓存中T实例的数量
*/
int count();
void setMaxSize(int max);
}
/**
* Created by LittleFogCat.
* <p>
* 自动适配屏幕像素的工具类。
* 需要先调用{@link ScreenUtil#init(Context)}才能正常使用。如果屏幕旋转,
* 那么需要再次调用{@link ScreenUtil#init(Context)}以更新。
*/
@SuppressWarnings({"unused", "WeakerAccess", "SuspiciousNameCombination"})
public class ScreenUtil {
private static final String TAG = "ScreenUtil";
/**
* 屏幕宽度,在调用init()之后通过{@link ScreenUtil#getScreenWidth()}获取
*/
private static int sScreenWidth = 1920;
/**
* 屏幕高度,在调用init()之后通过{@link ScreenUtil#getScreenHeight()} ()}获取
*/
private static int sScreenHeight = 1080;
/**
* 设计宽度。用于{@link ScreenUtil#autoWidth(int)}
*/
private static int sDesignWidth = 1080;
/**
* 设计高度。用于{@link ScreenUtil#autoHeight(int)} (int)}
*/
private static int sDesignHeight = 1920;
/**
* 初始化ScreenUtil。在屏幕旋转之后,需要再次调用这个方法,否则计算将会出错。
*/
public static void init(Context context) {
DisplayMetrics m = context.getResources().getDisplayMetrics();
sScreenWidth = m.widthPixels;
sScreenHeight = m.heightPixels;
if (sDesignWidth > sDesignHeight != sScreenWidth > sScreenHeight) {
int tmp = sDesignWidth;
sDesignWidth = sDesignHeight;
sDesignHeight = tmp;
}
}
public static void setDesignWidthAndHeight(int width, int height) {
sDesignWidth = width;
sDesignHeight = height;
}
/**
* 根据实际屏幕和设计图的比例,自动缩放像素大小。
* <p>
* 例如设计图大小是1920像素x1080像素,实际屏幕是2560像素x1440像素,那么对于一个设计图中100x100像素的方形,
* 实际屏幕中将会缩放为133像素x133像素。这有可能导致图形的失真(当实际的横竖比和设计图不同时)
*
* @param origin 设计图上的像素大小
* @return 实际屏幕中的尺寸
*/
public static int autoSize(int origin) {
return autoWidth(origin);
}
/**
* 对于在横屏和竖屏下尺寸不同的物体,分别给出设计图的像素,返回实际屏幕中应有的像素。
*
* @param land 在横屏设计图中的像素大小
* @param port 在竖屏设计图中的像素大小
*/
public static int autoSize(int land, int port) {
return isPortrait() ? autoSize(port) : autoSize(land);
}
/**
* 根据屏幕分辨率自适应宽度。
*
* @param origin 设计图中的宽度,像素
* @return 实际屏幕中的宽度,像素
*/
public static int autoWidth(int origin) {
if (sScreenWidth == 0 || sDesignWidth == 0) {
return origin;
}
int autoSize = origin * sScreenWidth / sDesignWidth;
if (origin != 0 && autoSize == 0) {
return 1;
}
return autoSize;
}
/**
* 根据屏幕分辨率自适应高度
*
* @param origin 设计图中的高度,像素
* @return 实际屏幕中的高度,像素
*/
public static int autoHeight(int origin) {
if (sScreenHeight == 0 || sDesignHeight == 0) {
return origin;
}
int auto = origin * sScreenHeight / sDesignHeight;
if (origin != 0 && auto == 0) {
return 1;
}
return auto;
}
public static int getScreenWidth() {
return sScreenWidth;
}
public static void setScreenWidth(int w) {
sScreenWidth = w;
}
public static int getScreenHeight() {
return sScreenHeight;
}
public static void setScreenHeight(int h) {
sScreenHeight = h;
}
/**
* 是否是竖屏
*/
public static boolean isPortrait() {
return getScreenHeight() > getScreenWidth();
}
}