实现Android中TextView的跑马灯效果
转载请标明出处:http://blog.csdn.net/edisonchang/article/details/50000879
前几天一直下雪,早上过来上班,路上特别拥堵,还好赶上了早餐。回到工位后,刚入职不久的产品小鲜肉匆忙过来,希望我在应用列表的头部加一个跑马灯的文字滚动效果,并且能在中午能够看到结果。
对完需求后我就开始了调研和开发工作,因为Android的TextView天生支持跑马灯效果,所以一切看起来都是水到渠成,信手拈来。首先,使用android 原生的TextView控件实现走马灯的滚动效果,需要了解以下几项属性:
android:ellipsize="marquee" android:marqueeRepeatLimit="marquee_forever"
android:ellipsize=”marquee” 表示当文本长度大于View的宽度时以横向滚动方式显示;
android:marqueeRepeatLimit以设置滚动次数,marquee_forever表示无限循环 。
但是仅设置这两个属性,运行代码后TextView是没有滚动效果的,从Textview 实现跑马灯的源码可以看出TextView需要持有焦点才能实现跑马灯效果。
final TextView textView = mView.get(); if (textView != null && (textView.isFocused() || textView.isSelected())) { long currentMs = mChoreographer.getFrameTime(); long deltaMs = currentMs - mLastAnimationMs; mLastAnimationMs = currentMs; float deltaPx = deltaMs / 1000f * mPixelsPerSecond; mScroll += deltaPx; if (mScroll > mMaxScroll) { mScroll = mMaxScroll; mChoreographer.postFrameCallbackDelayed(mRestartCallback, MARQUEE_DELAY); } else { mChoreographer.postFrameCallback(mTickCallback); } textView.invalidate(); }
解决这个问题也不复杂,对我们的TextView加上
android:focusable=”true”
android:focusableInTouchMode=”true” 两个属性, 运行代码后TextView就自动滚动起来。从上面的例子可以看出TextView如果实现跑马灯效果,需要同时具备三个条件:
(1)android:ellipsize=”marquee”
(2)TextView单行显示,且内容必须超出TextView大小
(3)TextView要获得焦点
产品同学看了demo的跑马灯效果后,还是比较满意的,与此同时也提出另一些需求,他希望在列表的头部和一些特定的item里面都有滚动效果的TextView,并且可以同时滚动。 这一下确实还是有点为难,TextView要能滚动必须获得当前焦点,而对于一个View上的元素来讲,至多只有一个View能够获取焦点,所以多个TextView同时实现跑马灯效果,已经不是简单的配置就能满足需求了。
但是,我们还是很快就想到了解决方案。其实,从源码中,我们也可以看出,TextView的滚动显示与焦点有关系,一旦TextView失去焦点,TextView会立即停止滚动,所以要想实现多个TextView的同时跑马灯滚动,还得从TextView 的isFocused()方法入手。解决手段简单粗暴,我们直接重写isFocused()方法,让这个方法一直返回true, 果然多个TextView的跑马灯效果可以一并动起来了,示例代码如下:
public class MarqueeTextView extends TextView { public MarqueeTextView(Context context) { this(context, null); } public MarqueeTextView(Context context, AttributeSet attrs) { super(context, attrs); } public MarqueeTextView(Context context, AttributeSet attrs, int defStyle) { super(context, attrs, defStyle); } @Override public boolean isFocused() { return true; }}
但是事情往往没有想象中的顺利,将demo测试过的代码合到我们主程序时,却发现首次进入页面后ListView head 中的TextView 无法自动滚动,如果home键退出,或者切到其他页面再返回,就会顺利的滚动起来。
原因在于TextView启动跑马灯时,ListView并没有Layout完成,此时TextView的mLayout 为空 ,导致首次无法自动滚动,解决方法可以延时调用下 setSelected 方法,这里还有一些细节要注意,
@Override public void setSelected(boolean selected) { boolean wasSelected = isSelected(); super.setSelected(selected); if (selected != wasSelected && mEllipsize == TextUtils.TruncateAt.MARQUEE) { if (selected) { startMarquee(); } else { stopMarquee(); } } }
以上是setSelected方法的源码实现,从源码中我们发现如果原来TextView 已经是被选中状态,再次调用也是没有效果的,所以我们可以先调用 setSelected(false), 再调用 setSelected(true),这样一来就可以保证TextView的正常滚动 。
public void setText(String text) { super.setText(text); setHorizontallyScrolling(true); new Handler().postDelayed(new Runnable() { @Override public void run() { setSelected(false); setSelected(true); } }, 3000); }
至此,跑马灯效果顺利实现了,产品也效果也比较满意。如果您对文章内容有兴趣,请多多关注,有问题请回复
更多相关文章
- Android(安卓)Socket 通信实例...【Pnoker】
- Android中AVD的使用以及错误处理方法
- Android仿真翻页
- TextView一行显示一个文字效果
- Android笔试和面试常见题目(四)
- Android(安卓)自定义View练手Demo(三)实现微信拍一拍的动画效果
- Android屏蔽ListView的Item点击事件
- Android中下拉通知栏,Activity会走哪些生命周期?
- android实现图片翻转动画