【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必须单行显示,即内容必须 ...
随机推荐
- Ajax学习记录
Ajax 1:ajax是一种页面局部刷新的技术,不是整个页面刷新.这里就像论坛评论里面的刷新,只是局部的,不是页面全部提交到服务器. 2:页面不刷新,创建个WebClient,它和服务器进行交互.&l ...
- [转]俞敏洪:我和马云就差了8个字... [来自: news.mbalib.com]
我和马云差了 8 个字:越败越战,愈挫愈勇. 马云,我真的非常的佩服他,首先佩服他的是他跟我有同样的经历,我考了 3 年才考上了大学:他也是考了 3 年.我比他还要幸运一点,我考上的是北大的本科,马云 ...
- 背水一战 Windows 10 (1) - C# 6.0 新特性
[源码下载] 背水一战 Windows 10 (1) - C# 6.0 新特性 作者:webabcd 介绍背水一战 Windows 10 之 C# 6.0 新特性 介绍 C# 6.0 的新特性 示例1 ...
- 【Java每日一题】20161017
20161014问题解析请点击今日问题下方的"[Java每日一题]20161017"查看 package Oct2016; import java.util.ArrayList; ...
- 世界那么Big,组件那么Small
推荐一个跨平台模块化App框架 -Small. Small,做最轻巧的跨平台插件化框架. 功能 完美内置 所有插件支持内置于宿主包中 高度透明 插件编码.布局编写方式与独立应用开发无异 插件代码调试与 ...
- Scalaz(4)- typeclass:标准类型-Equal,Order,Show,Enum
Scalaz是由一堆的typeclass组成.每一个typeclass具备自己特殊的功能.用户可以通过随意多态(ad-hoc polymorphism)把这些功能施用在自己定义的类型上.scala这个 ...
- JVM堆和栈的区别
物理地址 堆的物理地址分配对对象是不连续的.因此性能慢些.在GC的时候也要考虑到不连续的分配,所以有各种算法.比如,标记-消除,复制,标记-压缩,分代(即新生代使用复制算法,老年代使用标记--压缩) ...
- js控制页面显示和表单提交
早期的web页面在显示方面一般在后台进行控制,虽然对后台开发来讲是比较容易做到的,但是涉及到一个问题,那就是数据库压力. 因为要控制显示,所以会比较频繁的从数据库中来回调用. 现在的js功能越来越强, ...
- 编译安装php-amq扩展
用途:这个扩展是用来操作rabbitmq服务端的 一.安装总括 1.编译安装librabbitmq库 这是一个开源c语言的库.用来与rabbitmq进行通信 而php的php-amqp扩展就是使用这个 ...
- Android总结篇系列:Android广播机制
1.Android广播机制概述 Android广播分为两个方面:广播发送者和广播接收者,通常情况下,BroadcastReceiver指的就是广播接收者(广播接收器).广播作为Android组件间的通 ...