Android 可以自定义速度的跑马灯效果

android:singleLine="true"  
android:ellipsize="marquee"
 android:focusable="true" 

这三个属性就可以实现跑马灯的效果,但是这种做法只适用于一个TextView,如果想让两个以上的TextView跑起来就需要自定义TextView。

让两个以上的TextView以默认的滚动方式、滚动速度跑起来很简单,只需要在自定义TextView中重写isFocused方法,然后将返回值改为true,代码如下:

public class CarouselTextView extends TextView{

    public CarouselTextView(Context context) {
        super(context);
    }
    
    public CarouselTextView(Context context, AttributeSet attrs, int defStyle) {
        super(context, attrs, defStyle);
    }

    public CarouselTextView(Context context, AttributeSet attrs) {
        super(context, attrs);
    }
      /**
     * 获取焦点,不重写不能滚动
     */
    @Override
    public boolean isFocused() {
        return true;
    }

布局如下:

 <com.fm.carouseltextview.widget.CarouselTextView 
            android:id="@+id/tv_carousel_two"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_below="@+id/tv_carousel_one"
            android:layout_marginTop="20dp"
            android:text="@string/carousel_text"
            android:marqueeRepeatLimit="marquee_forever"
            android:singleLine="true"
            android:ellipsize="marquee"
        /> 
         <com.fm.carouseltextview.widget.CarouselTextView 
            android:id="@+id/tv_carousel_three"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_below="@+id/tv_carousel_two"
            android:layout_marginTop="20dp"
            android:text="@string/carousel_text"
            android:singleLine="true"
            android:ellipsize="marquee"
            android:marqueeRepeatLimit="marquee_forever"
        /> 

其中android:marqueeRepeatLimit="marquee_forever" 这个属性是设置无限重复,如果不设置的话,默认会在3次之后停止不动了。
android.widget.TextView类里设置的属性如下:

private int mMarqueeRepeatLimit = 3;
/**
     * Sets how many times to repeat the marquee animation. Only applied if the
     * TextView has marquee enabled. Set to -1 to repeat indefinitely.
     *
     * @see #getMarqueeRepeatLimit()
     *
     * @attr ref android.R.styleable#TextView_marqueeRepeatLimit
     */
    public void setMarqueeRepeatLimit(int marqueeLimit) {
        mMarqueeRepeatLimit = marqueeLimit;
    }

下面再来说说自定义速度的跑马灯效果:

其实,跑马灯效果就是不断的滚动位置,而自定义速度的跑马灯就是以自定义的时间间隔去滚动位置,明白了这个思想之后,做起来就比较的简单了。

首先以自定义的时间间隔去滚动位置,就需要不断地执行滚动的操作,所以我们可以用一个线程来执行这个滚动的操作,这里用的方法是实现Runnable接口,重写run方法来实现的。

/**
     * 执行滚动
     */
    @Override
    public void run() {
        Log.d(TAG, "run");
        currentScrollX += speed;  // 滚动速度每次加几个点
        scrollTo(currentScrollX, 0); // 滚动到指定位置
        if(isStop){   
            return;
        }
        if(currentScrollX >= endX){   // 如果滚动的位置大于最大限度则滚动到初始位置
            scrollTo(firstScrollX, 0);
            currentScrollX = firstScrollX; // 初始化滚动速度
            postDelayed(this, SCROLL_DELAYED);  // SCROLL_DELAYED毫秒之后重新滚动
        }else {
            postDelayed(this, delayed);  // delayed毫秒之后再滚动到指定位置
        }
        
    }

其次,在显示TextView控件的过程中,会有一些回调方法,而滚动的属性和参数都需要进行初始化,所以,我们可以通过这些回调方法中进行初始化操作。代码如下:

@Override
    protected void onTextChanged(CharSequence text, int start, int lengthBefore, int lengthAfter) {
        super.onTextChanged(text, start, lengthBefore, lengthAfter);
        Log.d(TAG , "onTextChanged");
        isStop = true; // 停止滚动
        this.removeCallbacks(this);   // 清空队列
        currentScrollX = firstScrollX;  // 滚动到初始位置
        this.scrollTo(currentScrollX, 0);
        super.onTextChanged(text, start, lengthBefore, lengthAfter);
        // 需要重新设置参数
        isFirstDraw = true;  
        isStop = false;
        postDelayed(this, SCROLL_DELAYED);
    }

@Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
        if (isFirstDraw) {
            Log.d(TAG , "isFirstDraw=="+isFirstDraw);
            getTextWidth();
            firstScrollX = getScrollX(); // 获取第一次滑动的X轴距离
            System.out.println("firstScrollX======"+firstScrollX);
            currentScrollX = firstScrollX;
            mWidth = this.getWidth();  // 获取文本宽度,如果文本宽度大于屏幕宽度,则为屏幕宽度,否则为文本宽度
            Log.d(TAG , "mWidth======"+mWidth);
            endX = firstScrollX + textWidth - mWidth/2;  // 滚动的最大距离,可根据需要来定
            Log.d(TAG , "endX========"+endX);
            isFirstDraw = false;
        }
    }

另外将一些滚动速度的一些属性和控制滚动速度的操作贴出来:

        private static final String TAG = "CarouselTextView";
    private int currentScrollX = 0; // 当前滚动位置  X轴
    private int firstScrollX = 0;  //  初始位置
    private boolean isStop = false;  // 开始停止的标记
    private int textWidth;  // 文本宽度
    private int mWidth = 0; // 控件宽度
    private int speed = 2;  // 默认是两个点
    private int delayed = 1000; // 默认是1秒
    private int endX; // 滚动到哪个位置
    private boolean isFirstDraw=true; // 当首次或文本改变时重置
    private static final int SCROLL_DELAYED = 4 * 1000;

/**
     * @param 滚动速度
     */
    public void setSpeed(int speed) {
        this.speed = speed;
    }


    /**
     * @param 滚动时间间隔
     */
    public void setDelayed(int delayed) {
        this.delayed = delayed;
    }

      /**
     * 开始滚动
     */
    public void startScroll() {
        isStop = false;
        this.removeCallbacks(this);  // 清空队列
        postDelayed(this, SCROLL_DELAYED);  // 4秒之后滚动到指定位置
    }
    
    /**
     * 停止滑动
     */
    public void stopScroll() {
        isStop = true;
    }
    
    /**
     * 从头开始滑动
     */
    public void startFor(){
        currentScrollX = 0;  // 将当前位置置为0
        startScroll();
    }

最后贴上布局设置:

<com.fm.carouseltextview.widget.CarouselCustomerSpeedTextView
        android:layout_below="@+id/tv_carousel_customer"
        android:id="@+id/tv_carousel_customer_one"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_marginTop="20dp"
        android:text="@string/carousel_text"
        android:singleLine="true" 
        android:ellipsize="marquee"/>

    <com.fm.carouseltextview.widget.CarouselCustomerSpeedTextView
        android:id="@+id/tv_carousel_customer_two"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_below="@+id/tv_carousel_customer_one"
        android:layout_marginTop="20dp"
        android:text="@string/carousel_text"
        android:singleLine="true"
        android:ellipsize="marquee" />

效果图如下:

test.gif

注意:如果设置了android:marqueeRepeatLimit="marquee_forever"属性之后,所有的速度设置都是无效的。
做这个效果之前,本人在网上找了许多篇博客,上面的这些代码也是从别人的博客中找来的,然后根据自己的理解,写下这个博客,给大家做个参考,如果有说的不对的地方,欢迎指出。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 218,284评论 6 506
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 93,115评论 3 395
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 164,614评论 0 354
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,671评论 1 293
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,699评论 6 392
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,562评论 1 305
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,309评论 3 418
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 39,223评论 0 276
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,668评论 1 314
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,859评论 3 336
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,981评论 1 348
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,705评论 5 347
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,310评论 3 330
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,904评论 0 22
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 33,023评论 1 270
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 48,146评论 3 370
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,933评论 2 355

推荐阅读更多精彩内容