Android 原生的跑马灯 MarqueeTextView
前段时间需求中有一个横向滚动公告(多条)功能,TextView采用自带的跑马灯效果时无法完全满足我的标准,因此在网上查找其它解决方案,找了不同方法实现的案例,但整体效果都不太理想,要么存在缺陷,最终找到xiaweizi/MarqueeTextView这个方案,感谢作者gitHub的开源项目。
优化后的具体代码已分享到GitHub liyazhou0221/LeaningProject需要下载的请前往下载
一、方案优点
1、原理:本方案在Android中的TextView自带跑马灯效果的基础上,通过Scroller控制器来控制整个View的滚动。
2、功能:控制滚动时间(速度)、控制滚动延迟、控制滚动模式、生命周期可以自己控制(暂停-继续-重新开始-停止)
二、新增优化内容(在原有的基础上新增部分内容)
1、支持多条数据
2、为每条数据添加点击事件监听
3、添加自定义滚动速度控制
三、具体使用方法
Java代码:
noticeTextV.setOnItemClickListener(new MarqueeTextView.OnMarqueeItemClickListener() {
@Override
public void onClick(int position) {
// 根据点击位置获取具体是那个公告
JSONObject jsonObject = noticeArray.getJSONObject(position);
// ...
}
@Override
public String[] initShowTextList() {
// 根据需要显示的内容,生成显示数组对象
String[] strings = new String[noticeArray.size()];
for (int i = 0; i < noticeArray.size(); i++) {
strings[i] = noticeArray.getJSONObject(i).getString("key");
}
return strings;
}
});
noticeTextV.startScroll();
2、xml配置
<!--横向滚动公告-->
<declare-styleable name="MarqueeTextView">
<!--滚动时长毫秒-->
<attr name="scroll_interval" format="integer" />
<attr name="scroll_speed" format="integer" />
<attr name="scroll_first_delay" format="integer" />
<attr name="scroll_mode">
<enum name="mode_forever" value="100" />
<enum name="mode_once" value="101" />
</attr>
</declare-styleable>
<MarqueeTextView
android:id="@+id/notice_text"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_centerVertical="true"
android:orientation="horizontal"
android:textColor="@color/md_orange_EC8423"
android:textSize="?text_size_normal"
app:scroll_first_delay="0"
app:scroll_mode="mode_forever"
app:scroll_speed="100" />
四、具体实现
1、支持多条数据
/**
* 添加显示的公告列表,并
* @param list
*/
public void setData(String[] list) {
this.listData = list;
showTextData = getShowTextData();
setText(showTextData);
}
/**
* 拼接显示字符串,并计算出每个item所在的位置
* @return
*/
private String getShowTextData() {
if (listData != null && listData.length > 0) {
listDataPos = new int[listData.length];
StringBuilder showData = new StringBuilder();
for (int i = 0; i < listData.length; i++) {
showData.append(listData[i]);
// 每一条后都添加空格占位符
showData.append("\t\t\t\t");
listDataPos[i] = calculateScrollingLen(showData.toString());
}
return showData.toString();
} else {
return getText().toString();
}
}
/**
* 计算滚动的距离
* @return 滚动的距离
*/
private int calculateScrollingLen(String strTxt) {
if (TextUtils.isEmpty(strTxt)) {
return 0;
}
TextPaint tp = getPaint();
Rect rect = new Rect();
tp.getTextBounds(strTxt, 0, strTxt.length(), rect);
return rect.width();
}
2、为每条数据添加点击事件监听
// 手势监听
@Override
public boolean onTouchEvent(MotionEvent event) {
// 将触摸事件交给手势处理
mGestureDetector.onTouchEvent(event);
return true;//继续执行后面的代码
}
private GestureDetector.OnGestureListener gestureListener = new GestureDetector.SimpleOnGestureListener() {
@Override
public boolean onSingleTapConfirmed(MotionEvent e) {
// 点击事件 获取点击的位置
if (onItemClickListener != null) {
float clickX = mScroller.getCurrX() + e.getX();
for (int i = 0; i < listDataPos.length; i++) {
if (clickX >= 0 && clickX <= listDataPos[i]) {
onItemClickListener.onClick(i);
break;
}
}
}
return super.onSingleTapConfirmed(e);
}
};
3、添加自定义接口
/**
* 提供一个对外的初始化显示数据集合的方法
*
* @return 显示点数组
*/
public interface OnMarqueeItemClickListener {
void onClick(int position);
String[] initShowTextList();
}