最近项目有一个实现跑马灯效果的需求,需求很简单,就是单行文本(只有几个字)无限循环的效果,最开始也是百度和Github上找,找寻半天不是有BUG就是无法达到需求,最后在一位博主jixiaolong<microjixl@gmail.com>的github上借鉴了他所写的自定义View,该博主的自定义控件是作为多行文本使用的,但是该控件也有BUG,就是多行文本切换的太不自然,或者说,实际中用不成。因此本文介绍的控件只针对单行文本使用,滑动自然,不反人类,先看下效果:
废话不多说,奉上具体用法,再强调一遍,只适合单行文本!!!!!!!!!!!
1.自定义View
import java.util.List;
import android.annotation.SuppressLint;
import android.content.Context;
import android.graphics.Paint;
import android.text.TextUtils.TruncateAt;
import android.util.AttributeSet;
import android.view.Gravity;
import android.widget.TextView;
/**
* @author jixiaolong<microjixl@gmail.com>
*/
@SuppressLint("AppCompatCustomView")
public class BulletinView extends TextView implements Runnable{
private int currentScrollX;// 当前滚动的位置
private boolean isStop = false;
private int textWidth;
private List<String> mList;
private final int REPEAT = 1;
private int repeatCount = 0;
private int currentNews = 0;
public BulletinView(Context context) {
super(context);
init();
// TODO Auto-generated constructor stub
}
public BulletinView(Context context, AttributeSet attrs) {
super(context, attrs);
init();
}
public BulletinView(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
init();
}
public void init(){
setClickable(true);
setSingleLine(true);
setEllipsize(TruncateAt.MARQUEE);
setGravity(Gravity.START|Gravity.CENTER_VERTICAL);
}
public void setData(List<String> mList){
if(mList == null || mList.size()==0){
return;
}
this.mList = mList;
currentNews = 0;
String n = mList.get(currentNews);
setText(n);
setTag(n);
startScroll();
}
@Override
public void setText(CharSequence text, BufferType type) {
super.setText(text, type);
MeasureTextWidth();
}
@Override
public void onScreenStateChanged(int screenState) {
super.onScreenStateChanged(screenState);
if(screenState == SCREEN_STATE_ON){
startScroll();
}else{
stopScroll();
}
}
/**
* 获取文字宽度
*/
private void MeasureTextWidth() {
Paint paint = this.getPaint();
String str = this.getText().toString();
textWidth = (int) paint.measureText(str);
}
@Override
public void run() {
if(textWidth < 1){
//title null api error.
if(mList != null && mList.size() > 0){
nextNews();
}else{
return;
}
}
currentScrollX += 5;// 滚动速度
scrollTo(currentScrollX, 0);
if (isStop) {
return;
}
if (getScrollX() >= textWidth) {
currentScrollX = -getWidth();
if(repeatCount >= REPEAT){
//reach max times 我对原文的修改只有这么一点 start
if (mList.size()==1){
scrollTo(currentScrollX, 0);
}else {
nextNews();
scrollTo(currentScrollX,0);
}
//我对原文的修改只有这么一点 end
}else{
repeatCount ++;
}
}
postDelayed(this, 50);
}
private void nextNews(){
repeatCount = 0;
currentNews ++;
currentNews = currentNews%mList.size();//cycle index
String n = mList.get(currentNews);
setText(n);
setTag(n);
}
// 开始滚动
public void startScroll() {
isStop = false;
this.removeCallbacks(this);
post(this);
}
// 停止滚动
public void stopScroll() {
isStop = true;
}
}
2.xml使用
3.Activity使用<?xml version="1.0" encoding="utf-8"?> <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" android:orientation="vertical" android:layout_width="match_parent" android:layout_height="match_parent"> <com.anshi.chattraining.BulletinView android:id="@+id/tv_bulletin" android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_alignParentTop="true" android:textColor="@android:color/white" android:padding="10dp" android:background="#b0000000" android:textSize="20sp" /> </RelativeLayout>
end.........................就这样把,其他的用SurfaceView做的多半都有些问题,还是用TextView做吧。博主原文地址import android.os.Bundle; import android.support.annotation.Nullable; import android.support.v7.app.AppCompatActivity; import java.util.ArrayList; import java.util.List; /** * * Created by yulu on 2017/12/12. */ public class MarqueeActivity extends AppCompatActivity { private BulletinView view; @Override protected void onCreate(@Nullable Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.marquee_activity); view = (BulletinView) findViewById(R.id.tv_bulletin); List<String> mList = new ArrayList<>(); mList.add("今天共找寻成功22对"); view.setData(mList); } @Override protected void onResume() { view.startScroll(); super.onResume(); } @Override protected void onPause() { view.stopScroll(); super.onPause(); } }