前言

继承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跑马灯的更多相关文章

  1. 【Android】不依赖焦点和选中的TextView跑马灯【2】

    前言 之前有写一篇TextView跑马灯的效果,后来实际项目中有发现新的问题,比如还是无法自动跑,文本超过了显示区域就截取的问题,今天换了一种思路来实现,更简单更好用. 声明 欢迎转载,但请保留文章原 ...

  2. [Android1.5]TextView跑马灯效果

    from: http://www.cnblogs.com/over140/archive/2010/08/20/1804770.html 前言 这个效果在两周前搜索过,网上倒是有转载,可恨的是转载之后 ...

  3. Android:TextView跑马灯-详解

    Android:TextView跑马灯_详解 引言: TextView之所以需要跑马灯,是由于文字太长,或者是吸引眼球. 关键代码如下: android:singleLine="true&q ...

  4. 【Android】TextView跑马灯效果

    老规矩,先上图看效果. 说明 TextView的跑马灯效果也就是指当你只想让TextView单行显示,可是文本内容却又超过一行时,自动从左往右慢慢滑动显示的效果就叫跑马灯效果. 其实,TextView ...

  5. TextView 跑马灯

    首先,写一个类,让其继承自TextView: 重写focus方法,让TextView始终是focus. public class MarqueeText extends TextView { publ ...

  6. TextView跑马灯

    TextView跑马灯 textView跑马灯实现:1.定义textView标签的4个属性:android:singleLine="true"//使其只能单行android:ell ...

  7. Third Day:正式编程第三天,学习实践内容TextView跑马灯、AutoCompleteTextView、multiAutoCompleteTextView以及ToggleButton、checkedBox、RadioButton等相关实践

    2.针对Focused的TextView跑马灯(文字较多一行无法显示)效果 针对单个TextView的跑马灯效果,可直接在TextView控件参数中添加三个属性: android:singleLine ...

  8. android textview 跑马灯

    <TextView android:layout_width="match_parent" android:layout_height="48dp" an ...

  9. Android学习总结——TextView跑马灯效果

    Android系统中TextView实现跑马灯效果,必须具备以下几个条件: 1.android:ellipsize="marquee" 2.TextView必须单行显示,即内容必须 ...

随机推荐

  1. 用redux构建购物车

    很久没更新博客了,最近要用到react,再来跟大家分享一个redux案例吧. [ {"id": 1, "title": "iPad 4 Mini&qu ...

  2. Hive SQL 监控系统 - Hive Falcon

    1.概述 在开发工作当中,提交 Hadoop 任务,任务的运行详情,这是我们所关心的,当业务并不复杂的时候,我们可以使用 Hadoop 提供的命令工具去管理 YARN 中的任务.在编写 Hive SQ ...

  3. Android Studio快捷键每日一练(4)

    原文地址:http://www.developerphil.com/android-studio-tips-of-the-day-roundup-4/ 33.分析数据流到当前位置 苹果/Windows ...

  4. JSONP实现跨域

    首先提出:什么是跨域?如何解决跨域? 跨域可以简单的理解为从一个域名访问另一个域名,由于javascript的同源政策的限制,出于安全的考虑,不允许浏览器这么做.比如a.com 域名下的js无法操作b ...

  5. 近期总结:generator-web,前端自动化构建的解决方案

    本文结合最近的工作经验,总结出一个较简洁的前端自动化构建方案,主张css和js的模块化,并通过grunt的自动化构建,有效地解决css合并,js合并和图片优化等问题,对于提高前端性能和项目代码质量有一 ...

  6. js实现数组的排序和分组

    问题: data=[1,1,1,1,2,2,2,2,5,5,5,8,8,8,2,2,2,3,3,3,3,3,3,3,3,3,3,4,4,4,4,4,4,4] 怎么把值为1,2,3,4,5,8的数据分成 ...

  7. Android 手机上获取物理唯一标识码[转]

    所有添加有谷歌账户的设备可以返回一个 ANDROID_ID 所有的CDMA设备对于 ANDROID_ID 和 TelephonyManager.getDeviceId() 返回相同的值(只要在设置时添 ...

  8. ASP.NET MVC程序播放H.264视频

    在这篇之前,Insus.NET不管是在ASP.NET还是ASP.NET MVC实现很多视频播放,你可以参考这篇链接:http://www.cnblogs.com/insus/category/4650 ...

  9. Swift注释

    Swift 中的普通注释与 Objective-C 中的一致,大概分为以下三种 // 单行注释 何问起 / *  多行注释 hovertree.com */ /// 标记注释1 http://hove ...

  10. ASP.NET MVC 模块与组件(二)——定制图片验证码

     本着简洁直接,我们就直奔主题吧! 下面是一个生成数字和字母随机组合的验证码类源代码: using System; using System.Drawing; using System.Drawing ...