最近做需求要写一个滚动弹幕的特效,要求是一直循环滚动,并且从左边出去部分的要从右边进入。
1.首先想到的是用Android TextView自带的跑马灯效果,设置一下android:ellipsize="marquee" ,但是发现这种方式局限性很强,只有文字的长度超过了TextView的长度才会滚动,并且只有全部滚动完成才会开启下一次的滚动。
2.参照GitHub - dreamgyf/MarqueeTextView: 走马灯式横向滚动的TextView(无论内容是否超过一行都会滚动)
原理是创建一个TextView,把他画在一个透明的canvas上,然后开启一个handler无限的去刷新绘制
canvas.drawBitmap(mBitmap, mLeftX, 0, getPaint());
if (mLeftX < 0) {
// 左边部分出去之后在右边绘制进入部分
canvas.drawBitmap(mBitmap, getWidth() + mLeftX + space, 0, getPaint());
}
3.使用scrollTo滑动
public class MarqueeView extends HorizontalScrollView implements Runnable {
private Context context;
private LinearLayout mainLayout;//跑马灯滚动部分
private int scrollSpeed = 5;//滚动速度
private int currentX;//当前x坐标
private int screenWidth;//屏幕宽度
public MarqueeView(Context context) {
this(context, null);
}
public MarqueeView(Context context, AttributeSet attrs) {
this(context, attrs, 0);
}
public MarqueeView(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
this.context = context;
initView();
}
void initView() {
WindowManager wm = (WindowManager) getContext().getSystemService(Context.WINDOW_SERVICE);
screenWidth = wm.getDefaultDisplay().getWidth();
mainLayout = (LinearLayout) LayoutInflater.from(context).inflate(R.layout.scroll_content, null);
this.addView(mainLayout);
}
//开始滚动
public void startScroll() {
removeCallbacks(this);
currentX = 0; // 开始滚动时候的位置
post(this);
}
//停止滚动
public void stopScroll() {
removeCallbacks(this);
}
@Override
public void run() {
mainLayout.scrollTo(currentX, 0);
currentX++;
if (currentX >= screenWidth) {
mainLayout.scrollTo(-screenWidth, 0);
currentX = -screenWidth;
}
postDelayed(this, 50 / scrollSpeed);
}
@Override
public boolean onTouchEvent(MotionEvent ev) {
return false;
}
}
这样一个类似跑马灯的布局就完成了,而要想实现我们的效果,只需要创建两个这样的布局,一个起始位置是0,一个起始位置是屏幕的宽度,然后循环移动位置即可。
于是我们只需要修改起始的位置即可
//开始滚动
public void startScroll(int site) {
removeCallbacks(this);
if (site == 0) {
currentX = 0; // 开始滚动时候的位置
} else {
currentX = -screenWidth;
}
post(this);
}