【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必须单行显示,即内容必须 ...
随机推荐
- [Asp.net 5] Configuration-新一代的配置文件(神奇的Binder)
关于配置文件的目录:[Asp.net 5] Configuration-新一代的配置文件 之前看过MVC4.0的源码,里面就有Binder.作用是将前台页面传递过来的键值对/字典表绑定到特定的对象.此 ...
- 【C#】在窗体中水平居中的控件,到了XP下不居中的解决办法
我时不时会遭遇这个操蛋问题,今天得闲研究了一下,解决如下: A.将窗体FormBorderStyle属性改为Fixed系,当然这会导致用户不能拖拉窗口大小,所以你可能需要B计划↓ B.确保在[VS]中 ...
- 如何使用C#创建WebService
使用C#创建WebService,服务端的webservice是必须,中间的soap,Xml我们不用去关心.下面是使用C#创建WebService的简单介绍. AD:51CTO技术沙龙 | 赋予APP ...
- C#中的枚举类型enum用法
定义一个简单的枚举类型: enum Days {Sat, Sun, Mon, Tue, Wed, Thu, Fri}; //这时候 Days.Sat = 0 ,后面依 ...
- C#的变迁史 - C# 4.0 之并行处理篇
前面看完了Task对象,这里再看一下另一个息息相关的对象Parallel. Parallel对象 Parallel对象封装了能够利用多核并行执行的多线程操作,其内部使用Task来分装多线程的任务并试图 ...
- 透过IL看C#:switch语句(转)
透过IL看C# switch语句(上) 摘要: switch语句是 C#中常用的跳转语句,可以根据一个参数的不同取值执行不同的代码.本文介绍了当向 switch语句中传入不同类型的参数时,编译器为其生 ...
- 不可或缺 Windows Native (24) - C++: 运算符重载, 自定义类型转换
[源码下载] 不可或缺 Windows Native (24) - C++: 运算符重载, 自定义类型转换 作者:webabcd 介绍不可或缺 Windows Native 之 C++ 运算符重载 自 ...
- 职责链模式(chain of responsibility)
一. 写在前面的 这么多的设计模式,我觉得职责链是我第一次看上去最简单,可是回想起来却又最复杂的一个模式. 因此,这个文章我酝酿了很久,一直也没有胆量发出来,例子也是改了又改,可是仍然觉得不够合理.所 ...
- SOA (面向服务的体系结构)
面向服务的体系结构是一个组件模型,它将应用程序的不同功能单元(称为服务)通过这些服务之间定义良好的接口和契约联系起来.接口是采用中立的方式进行定义的,它应该独立于实现服务的硬件平台.操作系统和编程语言 ...
- Scalaz(17)- Monad:泛函状态类型-State Monad
我们经常提到函数式编程就是F[T].这个F可以被视为一种运算模式.我们是在F运算模式的壳子内对T进行计算.理论上来讲,函数式程序的运行状态也应该是在这个运算模式壳子内的,也是在F[]内更新的.那么我们 ...