android textview实现走马灯效果

第一篇正好写一下正在弄的一个小软件上的这一块内容吧.

需求是在软件底部实现滚动文字广告的效果,当然肯定是在网上找了一下,找到了很多网页但是归结起来就是两种方法,我这里只写其中一种因为另外一种我也没实现出来。

一、首先把代码贴出来

1.新建一个TextView的扩展类,来实现自定义的滚动TextView控件效果,像下面这个AutoScrollAdsView.

  1 import android.content.Context;
  2 import android.graphics.Canvas;
  3 import android.graphics.Paint;
  4 import android.os.Bundle;
  5 import android.os.Parcel;
  6 import android.os.Parcelable;
  7 import android.util.AttributeSet;
  8 import android.util.DisplayMetrics;
  9 import android.widget.TextView;
 10 import android.view.View;
 11 import android.view.View.OnClickListener;
 12 import android.view.WindowManager;
 13 
 14 public class AutoScrollAdsView extends TextView implements OnClickListener {
 15 
 16     private static final float STEP = 2;
 17     
 18     private float mTextLength = 0f;
 19     private float mWidth = 0f;
 20     private float mStep = 0f;
 21     private float mY = 0f;
 22     private float mMinMarqueeLength = 0.0f;
 23     private float mMaxMarqueeLength = 0.0f;
 24     public boolean mScroll = false;
 25     private Paint mPaint = null;
 26     private String mText = "";
 27     
 28     public AutoScrollAdsView(Context context) {
 29         super(context);
 30         // TODO Auto-generated constructor stub
 31         setOnClickListener(this);
 32     }
 33 
 34     public AutoScrollAdsView(Context context, AttributeSet attrs, int defStyle) {
 35         super(context, attrs, defStyle);
 36         // TODO Auto-generated constructor stub
 37         setOnClickListener(this);
 38     }
 39 
 40     public AutoScrollAdsView(Context context, AttributeSet attrs) {
 41         super(context, attrs);
 42         // TODO Auto-generated constructor stub
 43         setOnClickListener(this);
 44     }
 45 
 46     @Override
 47     public void onClick(View v) {
 48         // TODO Auto-generated method stub
 49         if(mScroll){
 50             stopScroll();
 51         }else{
 52             startScroll();
 53         }
 54     }
 55 
 56     @Override
 57     public void onRestoreInstanceState(Parcelable state) {
 58         // TODO Auto-generated method stub
 59         super.onRestoreInstanceState(state);
 60     }
 61 
 62     @Override
 63     public Parcelable onSaveInstanceState() {
 64         // TODO Auto-generated method stub
 65         return super.onSaveInstanceState();
 66     }
 67     
 68     public void initView(WindowManager windowManager){
 69         mPaint = getPaint();
 70         mText = getText().toString();
 71         mTextLength = mPaint.measureText(mText);
 72         mWidth = getWidth();
 73         
 74         if(mWidth == 0){
 75             if(windowManager != null){
 76                 DisplayMetrics dm = new DisplayMetrics();
 77                 windowManager.getDefaultDisplay().getMetrics(dm);
 78                 mWidth = dm.widthPixels;
 79             }
 80         }
 81         
 82         mStep = mTextLength;
 83         mMinMarqueeLength = mWidth + mTextLength;
 84         mMaxMarqueeLength = mWidth + mTextLength * 2;
 85         mY = getTextSize() + getPaddingTop();
 86     }
 87     
 88     public static class SavedState extends BaseSavedState{
 89 
 90         public boolean scroll = false;
 91         public float step = 0f;
 92         
 93         public SavedState(Parcel arg0) {
 94             super(arg0);
 95             // TODO Auto-generated constructor stub
 96             Bundle bundle = new Bundle();
 97             bundle = arg0.readBundle();
 98             scroll = bundle.getBoolean("scroll");
 99             step = bundle.getFloat("step");
100         }
101 
102         public SavedState(Parcelable arg0) {
103             super(arg0);
104             // TODO Auto-generated constructor stub
105         }
106         
107         @Override
108         public void writeToParcel(Parcel dest, int flags) {
109             // TODO Auto-generated method stub
110             super.writeToParcel(dest, flags);
111             Bundle bundle = new Bundle();
112             bundle.putBoolean("scroll", scroll);
113             bundle.putFloat("step", step);
114             dest.writeBundle(bundle);
115         }
116 
117         public static final Parcelable.Creator<SavedState> CREATOR = 
118             new Parcelable.Creator<AutoScrollAdsView.SavedState>() {
119 
120                 @Override
121                 public SavedState createFromParcel(Parcel source) {
122                     // TODO Auto-generated method stub
123                     return new SavedState(source);
124                 }
125 
126                 @Override
127                 public SavedState[] newArray(int size) {
128                     // TODO Auto-generated method stub
129                     return new SavedState[size];
130                 }
131             };
132     }
133 
134     @Override
135     protected void onDraw(Canvas canvas) {
136         // TODO Auto-generated method stub
137         canvas.drawText(mText, mMinMarqueeLength - mStep, mY, mPaint);
138         
139         if(!mScroll){
140             return ;
141         }
142         
143         mStep += STEP;
144         if(mStep > mMaxMarqueeLength){
145             mStep = mTextLength;
146         }
147         
148         invalidate();
149     }
150     
151     public void startScroll(){
152         mScroll = true;
153         invalidate();
154     }
155     
156     public void stopScroll(){
157         mScroll = false;
158         invalidate();
159     }
160 }

2.待会儿再来说一说这个类的原理,紧接着是在xml中使用这个类,其中只要引用名称和id/layout等必要元素设置好,其他的自定义的一些东西都看你自己随意了

1 <com.xxxx.tmms.AutoScrollAdsView 
2         android:id="@+id/scroll_ads"
3         android:layout_width="match_parent"
4         android:layout_height="wrap_content"
5         android:textSize="25sp"
6         android:text="@string/scroll_tips"/>

3.在Activity中使用这个控件,其实也就三行代码

1 AutoScrollAdsView asav = (AutoScrollAdsView)findViewById(R.id.scroll_ads);
2 asav.initView(getWindowManager());
3 asav.startScroll();

这个时候运行就可以看到走马灯效果了,当然在这个基础上可以添加更多的功能,实现更加灵活多样的效果,就不再赘述了。

二、原理(这里纯用文字描述会有点儿乱)

接下来说一下这个AutoScrollAdsView这个class的原理,其实代码很简单,多看两遍再自己写一写就可以看懂。这里主要给一些刚开始学习的朋友一些参考和写出来对我自己也是一个记录。

要理解这个原理,主要是要了解mMinMarqueeLength,mMaxMarqueeLength和mStep这三个变量的意义。

本来画个图很容易说明,但是我画不好,就直接用文字来尝试解释一下了。

让一个字符串从TextView的右端往左端滚动,想象一下这个画面,其实就是开始时候在控件最右端绘制(这里姑且用这个词吧)字符串首字符,然后字符串往左移动一定的步长(就是mStep来控制的偏移量),重新绘制,然后再往左移动一点儿,再重新绘制,一直到字符串的末尾字符位移到控件的最左端。这样不断的重绘过程,就会表现出字符滚动的效果。

其实仔细想一想mMinMarqueeLength和mMaxMarqueeLength的值也可以有其他设置方法,因为一开始这段代码也是参照网上写下来的,我就顺着这个意思解释了。

mMinMarqueeLength这里设置是viewWidth + textLength.

从canvas.drawText(mText, mMinMarqueeLength - mStep, mY, mPaint);这个函数可以看出来,重绘的实现其实就是在控件的x/y坐标位置来显示某一字符串,所以初始的x坐标位置就是mMinMarqueeLength - mStep,其实就等于TextView控件的最右端。

然后mStep不断的自增,当mStep = mMinMarqueeLength时候,这个时候x坐标为0,但是这个时候这是表示字符串首字符在x为0的位置显示,只有当mStep = mMinMarqueeLength + textLength(也就是mMaxMarqueeLength)的时候,才代表字符串的完全绘制在TextView以外,也就是完成一次从左到右的移动。

然后这句if语句实现的就是循环滚动了,当mStep达到mMaxMarqueeLength以后,重新还原,然后再从头绘制

if(mStep > mMaxMarqueeLength){
    mStep = mTextLength;
}

而重绘操作其实是由invalidate()这个函数来实现的,具体这个函数的意思,可以自己google一下或者参考android官方网站的解释

三、最后当然是要感谢原作者的分享和聪明才智,转载至这个链接

http://www.pin5i.com/showtopic-26851.html

posted @ 2013-04-01 23:22  烟灰儿  阅读(434)  评论(0)    收藏  举报