自定义View—实现滚动TextView(跑马灯)效果

一般来说,自定义View需要以下四个步骤:

  • 自定义View的属性
  • 在View的构造方法中获得自定义的属性
  • 重写onMeasure方法
  • 重写onDraw方法

顾名思义,onMeasure方法是测量View的大小,而onDraw方法是绘制View。

先说下我们今天的目标,实现的是滚动的TextView,并且可以设置滚动的速度。值得高兴的是,实现这个功能只需要第四个步骤,,因此,实现起来比较简单,继承TextView,并且重写onDraw方法。

关于drawText方法

在Android中绘制字符串需要用到drawText方法:

drawText(String text, float x, float y, Paint paint)

text和paint就无须解释了,x和y是绘制的起点坐标。刚刚开始接触这个函数时,我是这样用的:

canvas.drawText(mText, 0, getMeasuredHeight() / 2, mPaint);

效果图

我们可以看到字符串偏上了,查阅资料发现drawText是以baseline为基准的,什么是baseline呢,看下图就可以明白:

自定义View—实现滚动TextView(跑马灯)效果_第1张图片

如果传入的y为getMeasuredHeight() / 2的话,字就会整体偏上。因此我们需要用到Paint.FontMetrics,Paint.FontMetrics可以根据字体的大小获得对应的top,ascent,descent,bottom的值,我们可以依次算出baseLine的值。

官方文档:
ascent:The recommended distance above the baseline for singled spaced text.
descent:The recommended distance below the baseline for singled spaced text.
top: The maximum distance above the baseline for the tallest glyph in the font at a given text size.
bottom:The maximum distance below the baseline for the lowest glyph in the font at a given text size.

ascent指的是baseLine到字符串顶端的距离,为负值;descent指的是baseLine到字符串底端的距离,为正值。运算时要注意正负。

因此 ( -ascent-descent )/2 是baseLine到center的距离,所以( -ascent-descent )/2+getMeasuredHeight() / 2 才应该是正确的y值,这里不明白的可以拿笔画下上面图,计算下就可以明白的。

这样以后的效果如下:
这里写图片描述

实现过程

刚刚开始时,我们将字符串绘制在View的右外界之外,不断然后让绘制起点向左移动,不断的绘制,这样就达到TextView想做滚动的效果。

@Override
    protected void onDraw(Canvas canvas) {
        float x, y;
        // offX 为横坐标偏移,一开始偏移为0,逐渐增大
        x = getMeasuredWidth() - offX;
        y = getMeasuredHeight() / 2 + (mPaint.descent() - mPaint.ascent()) / 2;
        canvas.drawText(mText, x, y, mPaint);
        // 增加横坐标偏移,左移绘制起点 ; mStep为偏移步伐
        offX += mStep;
        // mRect.width()为包含字符串的最小矩阵的宽度
        // 当偏移大于getMeasuredWidth() + mRect.width()时,说字符串尾巴都在View之外,归零偏移量
        if (offX >= getMeasuredWidth() + mRect.width()) {
            offX = 0f;
        }
        invalidate();
    }

我们有可能需要该表TextView滚动的速度,因此需要有个方法来提供对偏移步伐mStep的值。

    /**
     * 设置字幕滚动的速度
     */
    public void setScrollMode(int scrollMod) {
        if (scrollMod == SCROLL_SLOW) {
            mStep = 0.5f;
        } else if (scrollMod == SCROLL_NORM) {
            mStep = 1f;
        } else {
            mStep = 1.5f;
        }
    }

完善

我们发现系统的TextView过长时,会自动换行,因此onMeasure方法设置的Height是不符合我们的需求的,因为我们自定义的TextView是滚动的,高度是不用换行的,因此高度只是wrap_content或者是xml定义的。

因此,需要在构造函数里setSingleLine(true); 这样就不会换行,onMeasure里获得的Height是正确的。

使用

使用这个自定义的TextView,跟使用系统的TextView基本一样,不同的是可以设置滚动的速度,代码如下:

        t1 = (AutoTextView) findViewById(R.id.tv);
        t2 = (AutoTextView) findViewById(R.id.tv2);
        t3 = (AutoTextView) findViewById(R.id.tv3);
        // 设置滚动的速度
        t1.setScrollMode(AutoTextView.SCROLL_SLOW);
        t2.setScrollMode(AutoTextView.SCROLL_NORM);
        t3.setScrollMode(AutoTextView.SCROLL_FAST);

xml代码如下:

"http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:paddingBottom="@dimen/activity_vertical_margin"
    android:paddingLeft="@dimen/activity_horizontal_margin"
    android:paddingRight="@dimen/activity_horizontal_margin"
    android:paddingTop="@dimen/activity_vertical_margin"
    tools:context="com.jer.autotextview.TextActivity" >

    <com.jer.autotextview.AutoTextView
        android:id="@+id/tv2"
        android:layout_width="200dp"
        android:layout_height="wrap_content"
        android:layout_alignParentTop="true"
        android:layout_centerHorizontal="true"
        android:layout_marginTop="152dp"
        android:text="我仿佛感觉有人在背后说我帅.............................."
        android:textColor="#000000"
        android:textSize="22sp" />

    <com.jer.autotextview.AutoTextView
        android:id="@+id/tv"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_alignParentTop="true"
        android:layout_centerHorizontal="true"
        android:text="我有一个小苹果,就是不给你吃。如果你想要吃的话,就必须给我一个梨,因为我更喜欢吃梨"
        android:textColor="#000000"
        android:textSize="22sp" />

    <com.jer.autotextview.AutoTextView
        android:id="@+id/tv3"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_alignLeft="@+id/tv"
        android:layout_below="@+id/tv2"
        android:layout_marginTop="104dp"
        android:text="有人说我帅,我狠狠的扇了他一巴掌,你他妈这不是废话吗"
        android:textColor="#000000"
        android:textSize="18sp" />

实现好的效果图如下:
自定义View—实现滚动TextView(跑马灯)效果_第2张图片

附上官方文档关于Paint.FontMetrics和Canvas的介绍:
http://www.androidcommunitydocs.com/reference/android/graphics/Paint.FontMetrics.html
http://www.androidcommunitydocs.com/reference/android/graphics/Canvas.html

源码地址:http://download.csdn.net/detail/u012933743/8760149

你可能感兴趣的:(自定义View—实现滚动TextView(跑马灯)效果)