转载请注明出处:http://blog.csdn.net/CHX_W/article/details/74855521
最近一个朋友有个需求,需要实现多行文字自动向上翻滚的效果,上网找了很多没有特别满意的,只有一个demo其展示效果大体满意,其实现原理是通过onDraw方法动态画出来的效果,但是无法实现对每行的item点击响应事件,感觉改起来比较棘手,果断被pass掉自己写了一个,在这里将源码分享给需要的朋友!
思路
既要实现文字滚动又要实现点击的事件,最直观的想法就是创建多个TextView,通过遍历控件得到子View,先将第一个子View通过addView()添加进来,再将第一个子View删除,看上去就好像队列中的第一个人出队列排到最后依次循环达到伪轮播效果(此处有坑哦~)
使用说明
- 此控件传入的数据源为String集合,我们可以根据自己需要更改为对象也可以
- 开始调用:只需要在Activity或Fragment里通过setData()方法将数据传进来,剩下的就大胆的交给VerticalScrolledListview 控件吧!(当然记得要在xml里引用控件哦~)
- 点击事件监听已实现,需要自己手动调用哦~
注意的几点坑
- initTextView()方法需要在传入数据的时候被调用,如果直接放在初始化或者onDraw()中,控件显示为空,因为控件在初始化的时候数据还没有传进来!
- 注意了,反正我是被坑了一次,在操作子View的时候要注意需要先将要删除的remove掉,再添加,原因是必须先解除子view与父类关系,再添加进去,否则会报异常,就好比这个孩子已经有一个爸爸了,你硬把他塞给其他爸爸,一个孩子不可能有两个爸爸啊,所以必须把第一个爸爸给干掉,ok,合法了!
java.lang.IllegalStateException The specified child already has a parent. You must call removeView() on the child’s parent first - 大功告成!是不是很简单,哈哈~
完整VerticalScrolledListview代码如下
public class VerticalScrolledListview extends LinearLayout {
private Context mContext;
private List<String> data = new ArrayList<String>();
private OnItemClickListener itemClickListener;
public VerticalScrolledListview(Context context) {
super(context);
init(context);
}
public VerticalScrolledListview(Context context, @Nullable AttributeSet attrs) {
super(context, attrs);
init(context);
}
private void init(Context context){
mContext = context;
this.setOrientation(VERTICAL);
}
/**
* 更新文字需要在UI线程
*/
Handler mHandler = new Handler();
Runnable mUpdateResults = new Runnable() {
public void run() {
traversalView(VerticalScrolledListview.this);
}
};
private void initTextView(){
if (data != null && data.size() != 0){
for (int i = 0;i< data.size();i++){
TextView textView = new TextView(mContext);
textView.setText(data.get(i));
textView.setGravity(Gravity.CENTER);
textView.setTextColor(Color.BLACK);
this.addView(textView);
textView.setClickable(true);
final int index = i;
textView.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
itemClickListener.onItemClick(index);
}
});
}
//初始化控件结束调用计时器
startTimer();
}
}
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
}
/**
* @param data
* view初始化优先于此方法
* so控件需要手动调动填充
*/
public void setData(List<String> data){
this.data = data;
initTextView();
}
public void startTimer(){
Timer timer = new Timer();
TimerTask task = new TimerTask() {
@Override
public void run() {
//将数据源重新排序
mHandler.post(mUpdateResults);
}
};
timer.schedule(task, 2000, 2000);
}
/**
* 遍历view的所有子控件设值,不用在创建
* @param viewGroup
*/
public void traversalView(final ViewGroup viewGroup) {
if (viewGroup.getChildCount() != 0){
for (int i = 0; i < viewGroup.getChildCount(); i++){
if (i == 0){
mHandler.post(new Runnable() {
@Override
public void run() {
/**
* 此处必须这么处理,先removeview子view,解除与父类关系,再添加进去
* 否则会报错java.lang.IllegalStateException
*/
TextView newView = (TextView) viewGroup.getChildAt(0);
viewGroup.removeView(viewGroup.getChildAt(0));
viewGroup.addView(newView);
}
});
}
}
}
}
/**
* 设置点击事件监听
* @param itemClickListener
*/
public void setOnItemClickListener(VerticalScrolledListview.OnItemClickListener itemClickListener) {
this.itemClickListener = itemClickListener;
}
/**
* 轮播文本点击监听器
*/
public interface OnItemClickListener {
/**
* @param position 当前点击ID
*/
void onItemClick(int position);
}
}