【Android】不依赖焦点和选中的TextView跑马灯
前言
继承TextView,并仿照源码修改而来,主要是取消了焦点和选中了判断,也不依赖文本的宽度。
声明
欢迎转载,但请保留文章原始出处:)
博客园:http://www.cnblogs.com
农民伯伯: http://over140.cnblogs.com
正文
import java.lang.ref.WeakReference; import android.content.Context;
import android.graphics.Canvas;
import android.os.Handler;
import android.os.Message;
import android.util.AttributeSet;
import android.widget.TextView; public class MarqueeTextView extends TextView { private Marquee mMarquee; public MarqueeTextView(Context context, AttributeSet attrs) {
super(context, attrs);
} public MarqueeTextView(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
} public MarqueeTextView(Context context) {
super(context);
} public void startMarquee() {
startMarquee(-1);
} public void startMarquee(int repeatLimit) {
if (mMarquee == null)
mMarquee = new Marquee(this);
mMarquee.start(repeatLimit);
} public void stopMarquee() {
if (mMarquee != null && !mMarquee.isStopped()) {
mMarquee.stop();
}
} public void toggleMarquee() {
if (mMarquee == null || mMarquee.isStopped())
startMarquee();
else
stopMarquee();
} @Override
protected void onDraw(Canvas canvas) {
if (mMarquee != null && mMarquee.isRunning()) {
final float dx = -mMarquee.getScroll();
canvas.translate(getLayoutDirection() == LAYOUT_DIRECTION_RTL ? -dx
: +dx, 0.0f);
}
super.onDraw(canvas);
} @SuppressWarnings("unused")
private static final class Marquee extends Handler {
// TODO: Add an option to configure this
private static final float MARQUEE_DELTA_MAX = 0.07f;
private static final int MARQUEE_DELAY = 0;// 1200;
private static final int MARQUEE_RESTART_DELAY = 1200;
private static final int MARQUEE_RESOLUTION = 1000 / 30;
private static final int MARQUEE_PIXELS_PER_SECOND = 30; private static final byte MARQUEE_STOPPED = 0x0;
private static final byte MARQUEE_STARTING = 0x1;
private static final byte MARQUEE_RUNNING = 0x2; private static final int MESSAGE_START = 0x1;
private static final int MESSAGE_TICK = 0x2;
private static final int MESSAGE_RESTART = 0x3; private final WeakReference<TextView> mView; private byte mStatus = MARQUEE_STOPPED;
private final float mScrollUnit;
private float mMaxScroll;
private float mMaxFadeScroll;
private float mGhostStart;
private float mGhostOffset;
private float mFadeStop;
private int mRepeatLimit; private float mScroll; Marquee(TextView v) {
final float density = v.getContext().getResources()
.getDisplayMetrics().density;
mScrollUnit = (MARQUEE_PIXELS_PER_SECOND * density)
/ MARQUEE_RESOLUTION;
mView = new WeakReference<TextView>(v);
} @Override
public void handleMessage(Message msg) {
switch (msg.what) {
case MESSAGE_START:
mStatus = MARQUEE_RUNNING;
tick();
break;
case MESSAGE_TICK:
tick();
break;
case MESSAGE_RESTART:
if (mStatus == MARQUEE_RUNNING) {
if (mRepeatLimit >= 0) {
mRepeatLimit--;
}
start(mRepeatLimit);
}
break;
}
} void tick() {
if (mStatus != MARQUEE_RUNNING) {
return;
} removeMessages(MESSAGE_TICK); final TextView textView = mView.get();
// && (textView.isFocused() || textView.isSelected())
if (textView != null) {
mScroll += mScrollUnit;
if (mScroll > mMaxScroll) {
mScroll = mMaxScroll;
sendEmptyMessageDelayed(MESSAGE_RESTART,
MARQUEE_RESTART_DELAY);
} else {
sendEmptyMessageDelayed(MESSAGE_TICK, MARQUEE_RESOLUTION);
}
textView.invalidate();
}
} void stop() {
mStatus = MARQUEE_STOPPED;
removeMessages(MESSAGE_START);
removeMessages(MESSAGE_RESTART);
removeMessages(MESSAGE_TICK);
resetScroll();
} private void resetScroll() {
mScroll = 0.0f;
final TextView textView = mView.get();
if (textView != null) {
textView.invalidate();
}
} void start(int repeatLimit) {
if (repeatLimit == 0) {
stop();
return;
}
mRepeatLimit = repeatLimit;
final TextView textView = mView.get();
if (textView != null && textView.getLayout() != null) {
mStatus = MARQUEE_STARTING;
mScroll = 0.0f;
final int textWidth = textView.getWidth()
- textView.getCompoundPaddingLeft()
- textView.getCompoundPaddingRight();
final float lineWidth = textView.getLayout().getLineWidth(0);
final float gap = textWidth / 3.0f;
mGhostStart = lineWidth - textWidth + gap;
mMaxScroll = mGhostStart + textWidth;
mGhostOffset = lineWidth + gap;
mFadeStop = lineWidth + textWidth / 6.0f;
mMaxFadeScroll = mGhostStart + lineWidth + lineWidth; textView.invalidate();
sendEmptyMessageDelayed(MESSAGE_START, MARQUEE_DELAY);
}
} float getGhostOffset() {
return mGhostOffset;
} float getScroll() {
return mScroll;
} float getMaxFadeScroll() {
return mMaxFadeScroll;
} boolean shouldDrawLeftFade() {
return mScroll <= mFadeStop;
} boolean shouldDrawGhost() {
return mStatus == MARQUEE_RUNNING && mScroll > mGhostStart;
} boolean isRunning() {
return mStatus == MARQUEE_RUNNING;
} boolean isStopped() {
return mStatus == MARQUEE_STOPPED;
}
}
}
代码说明:
1、取消了焦点和选中的判断
2、将延迟1200改为0,立即执行跑马灯效果。
3、核心代码都是直接从TextView拷贝出来。
2014-04-25 更新
强烈建议参考本文的最新版本:【Android】不依赖焦点和选中的TextView跑马灯【2】
结束
这里主要是提供一种解决问题的思路,实际使用还需要进行相应的修改。
【Android】不依赖焦点和选中的TextView跑马灯的更多相关文章
- 【Android】不依赖焦点和选中的TextView跑马灯【2】
前言 之前有写一篇TextView跑马灯的效果,后来实际项目中有发现新的问题,比如还是无法自动跑,文本超过了显示区域就截取的问题,今天换了一种思路来实现,更简单更好用. 声明 欢迎转载,但请保留文章原 ...
- [Android1.5]TextView跑马灯效果
from: http://www.cnblogs.com/over140/archive/2010/08/20/1804770.html 前言 这个效果在两周前搜索过,网上倒是有转载,可恨的是转载之后 ...
- Android:TextView跑马灯-详解
Android:TextView跑马灯_详解 引言: TextView之所以需要跑马灯,是由于文字太长,或者是吸引眼球. 关键代码如下: android:singleLine="true&q ...
- 【Android】TextView跑马灯效果
老规矩,先上图看效果. 说明 TextView的跑马灯效果也就是指当你只想让TextView单行显示,可是文本内容却又超过一行时,自动从左往右慢慢滑动显示的效果就叫跑马灯效果. 其实,TextView ...
- TextView 跑马灯
首先,写一个类,让其继承自TextView: 重写focus方法,让TextView始终是focus. public class MarqueeText extends TextView { publ ...
- TextView跑马灯
TextView跑马灯 textView跑马灯实现:1.定义textView标签的4个属性:android:singleLine="true"//使其只能单行android:ell ...
- Third Day:正式编程第三天,学习实践内容TextView跑马灯、AutoCompleteTextView、multiAutoCompleteTextView以及ToggleButton、checkedBox、RadioButton等相关实践
2.针对Focused的TextView跑马灯(文字较多一行无法显示)效果 针对单个TextView的跑马灯效果,可直接在TextView控件参数中添加三个属性: android:singleLine ...
- android textview 跑马灯
<TextView android:layout_width="match_parent" android:layout_height="48dp" an ...
- Android学习总结——TextView跑马灯效果
Android系统中TextView实现跑马灯效果,必须具备以下几个条件: 1.android:ellipsize="marquee" 2.TextView必须单行显示,即内容必须 ...
随机推荐
- HBase相关
hadoop和hbase节点添加和单独重启 有时候hadoop或hbase集群运行时间久了后,某些节点就会失效,这个时候如果不想重启整个集群(这种情况在很多情况下已经不被允许),这个时候可以单独重启失 ...
- CocoaPods安装使用以及常见问题
什么是CocoaPods CocoaPods是iOS项目的依赖管理工具,该项目源码在Github上管理.开发iOS项目不可避免地要使用第三方开源库,CocoaPods的出现使得我们可以节省设置和第三方 ...
- 如何解读SQL Server日志(2/3)
接下来说说返回的RowLogo Content列,例子中返回了三个列.这些列包含了数据操作的"有效工作负载(Playload)"记录.根据不同操作类型有效负载的内容也是不同的,但是 ...
- 【转载】async & await 的前世今生(Updated)
async 和 await 出现在C# 5.0之后,给并行编程带来了不少的方便,特别是当在MVC中的Action也变成async之后,有点开始什么都是async的味道了.但是这也给我们编程埋下了一些隐 ...
- When using SqlDependency without providing an options value, SqlDependency.Start() must be called prior to execution of a command added to the SqlDependency instance.
在调试SignalR程序时,提示一个异常:When using SqlDependency without providing an options value, SqlDependency.Star ...
- Winform开发框架中实现同时兼容多种数据库类型处理
在很多应用系统里面,虽然一般采用一种数据库运行,但是由于各种情况的需要,可能业务系统会部署在不同类型的数据库上,如果开发的系统能够很方便支持多种数据库的切换,那可以为我们减少很多烦恼,同时提高系统的适 ...
- 分享一个递归无限级拼接Json的方法---ExtJs的TreePanel和TreeGrid均适用(Ef,Lambda,Linq,IQueryable,List)
话不多说,先上实体类,如果你不是codefirst,就把它当成数据表结构. 下面是底层BaseDal获取数据的方法 (如果你没有Base类,直接写在你的DAL层和BLL层) 下面是BaseServi ...
- C# Winform MD5加密学习积累
string password = txtPassword.Text.Trim(); byte[] result = Encoding.Default.GetBytes(password); MD5 ...
- webservice MaxReceivedMessageSize :已超过传入消息(65536)的最大消息大小配额
在客户端的webconfig文件的webservice节点进行如下配置:(注:此处客户端为应用程序的config文件) <system.serviceModel> <bindings ...
- css背景图