android 应用有时候需要做一个广告栏,可以做文字闪烁,跑马灯等效果,文字闪烁可以放在线程里面执行,多少秒过后设置文字的TextColor即可,跑马灯效果很少接触,之前写了一个demo,但是实现的效果不是自己想要的,普遍的跑马灯效果直接在layout里面的TextView控件加上如下属性即可实现:
android:marqueeRepeatLimit="marquee_forever"android:ellipsize="marquee" android:scrollHorizontally="true"android:focusableInTouchMode="true"android:focusable="true"
但是这种效果有一个致命的问题,文字的宽度必须要大于TextView设置的宽度(android:layout_width=”“),有时候需求文字很少,甚至根本没法实现跑马灯效果,这是让人头疼的事。
当然肯定有解决的办法,第一想到的就是自定义,急需要用的时候,自定义显得太麻烦了,耗时间,这里给大家介绍一个封装好的jar,下面一起来实现这个效果。
先要加入marquee的jar包,在项目的build.gradle文件中加入
compile 'com.dalong:marqueeview:1.0.0'
这里面只有一个类,自定义的MarqueeView,简单的来看一下:
package com.dalong.marqueeview;import android.content.Context;import android.content.res.TypedArray;import android.graphics.Canvas;import android.graphics.Color;import android.graphics.Paint;import android.os.Handler;import android.os.Message;import android.text.TextPaint;import android.text.TextUtils;import android.util.AttributeSet;import android.util.Log;import android.view.SurfaceHolder;import android.view.SurfaceView;import android.view.WindowManager;/*** Created 16/5/15.*/public class MarqueeView extends SurfaceView implements SurfaceHolder.Callback{public Context mContext;private float mTextSize = 100; //字体大小private int mTextColor = Color.RED; //字体的颜色private int mBackgroundColor=Color.WHITE;//背景色private boolean mIsRepeat;//是否重复滚动private int mStartPoint;// 开始滚动的位置 0是从最左面开始 1是从最末尾开始private int mDirection;//滚动方向 0 向左滚动 1向右滚动private int mSpeed;//滚动速度private SurfaceHolder holder;private TextPaint mTextPaint;private MarqueeViewThread mThread;private String margueeString;private int textWidth=0,textHeight=0;private int ShadowColor=Color.BLACK;public int currentX=0;// 当前x的位置public int sepX=5;//每一步滚动的距离public MarqueeView(Context context) {this(context,null);}public MarqueeView(Context context, AttributeSet attrs) {this(context, attrs,0);}public MarqueeView(Context context, AttributeSet attrs, int defStyleAttr) {super(context, attrs, defStyleAttr);this.mContext=context;init(attrs, defStyleAttr);}private void init(AttributeSet attrs, int defStyleAttr) {TypedArray a = getContext().obtainStyledAttributes(attrs, R.styleable.MarqueeView, defStyleAttr, 0);mTextColor = a.getColor(R.styleable.MarqueeView_textcolor, Color.RED);mTextSize = a.getDimension(R.styleable.MarqueeView_textSize, 48);mBackgroundColor=a.getColor(R.styleable.MarqueeView_marqueebackground,Color.BLACK);mIsRepeat=a.getBoolean(R.styleable.MarqueeView_isRepeat,false);mStartPoint=a.getInt(R.styleable.MarqueeView_startPoint,0);mDirection=a.getInt(R.styleable.MarqueeView_direction,0);mSpeed=a.getInt(R.styleable.MarqueeView_speed,20);a.recycle();holder = this.getHolder();holder.addCallback(this);mTextPaint = new TextPaint();mTextPaint.setFlags(Paint.ANTI_ALIAS_FLAG);mTextPaint.setTextAlign(Paint.Align.LEFT);}public void setText(String msg){if(!TextUtils.isEmpty(msg)){measurementsText(msg);}}protected void measurementsText(String msg) {margueeString=msg;mTextPaint.setTextSize(mTextSize);mTextPaint.setColor(mTextColor);mTextPaint.setStrokeWidth(0.5f);mTextPaint.setFakeBoldText(true);// 设定阴影(柔边, X 轴位移, Y 轴位移, 阴影颜色)// mTextPaint.setShadowLayer(5, 3, 3, ShadowColor);textWidth = (int)mTextPaint.measureText(margueeString);Paint.FontMetrics fontMetrics = mTextPaint.getFontMetrics();textHeight = (int) fontMetrics.bottom;WindowManager wm = (WindowManager) mContext.getSystemService(Context.WINDOW_SERVICE);int width = wm.getDefaultDisplay().getWidth();if(mStartPoint==0)currentX=0;elsecurrentX=width-getPaddingLeft()-getPaddingRight();}@Overridepublic void surfaceCreated(SurfaceHolder holder) {this.holder=holder;}@Overridepublic void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {if(mThread!=null)mThread.isRun = true;}@Overridepublic void surfaceDestroyed(SurfaceHolder holder) {if(mThread!=null)mThread.isRun = false;}/*** 开始滚动*/public void startScroll(){if(mThread!=null&&mThread.isRun)return;mThread = new MarqueeViewThread(holder);//创建一个绘图线程mThread.start();}/*** 停止滚动*/public void stopScroll(){if(mThread!=null){mThread.isRun = false;mThread.interrupt();}mThread=null;}/*** 线程*/class MarqueeViewThread extends Thread{private SurfaceHolder holder;public boolean isRun ;//是否在运行public MarqueeViewThread(SurfaceHolder holder) {this.holder =holder;isRun = true;}public void onDraw() {try {synchronized (holder) {if (TextUtils.isEmpty(margueeString)) {Thread.sleep(1000);//睡眠时间为1秒return;}Canvas canvas = holder.lockCanvas();int paddingLeft = getPaddingLeft();int paddingTop = getPaddingTop();int paddingRight = getPaddingRight();int paddingBottom = getPaddingBottom();int contentWidth = getWidth() - paddingLeft - paddingRight;int contentHeight = getHeight() - paddingTop - paddingBottom;int centeYLine = paddingTop + contentHeight / 2;//中心线if(mDirection==0) {//向左滚动if(currentX <=-textWidth){if(!mIsRepeat){//如果是不重复滚动mHandler.sendEmptyMessage(ROLL_OVER);}currentX=contentWidth;}else{currentX-=sepX;}}else {// 向右滚动if(currentX>=contentWidth){if(!mIsRepeat){//如果是不重复滚动mHandler.sendEmptyMessage(ROLL_OVER);}currentX=-textWidth;}else{currentX+=sepX;}}if(canvas!=null)canvas.drawColor(mBackgroundColor);canvas.drawText(margueeString,currentX, centeYLine+dip2px(getContext(),textHeight)/2,mTextPaint);holder.unlockCanvasAndPost(canvas);//结束锁定画图,并提交改变。int a=textWidth/margueeString.trim().length();int b=a/sepX;int c=mSpeed/b==0?1:mSpeed/b;Thread.sleep(c);//睡眠时间为移动的频率}}catch (Exception e) {e.printStackTrace();}}@Overridepublic void run() {while (isRun) {onDraw();}}}public static final int ROLL_OVER =100;Handler mHandler=new Handler(){@Overridepublic void handleMessage(Message msg) {super.handleMessage(msg);switch (msg.what){case ROLL_OVER:stopScroll();if(mOnMargueeListener!=null){mOnMargueeListener.onRollOver();}break;}}};/*** dip转换为px* @param context* @param dpValue* @return*/public static int dip2px(Context context, float dpValue) {final float scale = context.getResources().getDisplayMetrics().density;return (int) (dpValue * scale + 0.5f);}public void reset(){int contentWidth = getWidth() - getPaddingLeft() - getPaddingRight();if(mStartPoint==0)currentX=0;elsecurrentX=contentWidth;}/*** 滚动回调*/public interface OnMargueeListener{void onRollOver();//滚动完毕}OnMargueeListener mOnMargueeListener;public void setOnMargueeListener(OnMargueeListener mOnMargueeListener){this.mOnMargueeListener=mOnMargueeListener;}}
以上代码写明了注释,就不多说了,大家可以了解下。
下面先写一个xml布局文件:
<?xml version="1.0" encoding="utf-8"?><LinearLayout xmlns:android="/apk/res/android"xmlns:app="/apk/res-auto"android:layout_width="match_parent"android:layout_height="wrap_content"android:orientation="vertical"><LinearLayout android:layout_width="match_parent"android:layout_height="wrap_content"android:orientation="vertical"><com.dalong.marqueeview.MarqueeView android:id="@+id/tv_marquee"android:layout_width="match_parent"android:layout_height="wrap_content"app:direction="left"app:isRepeat="true"app:speed="50"app:startPoint="end"app:textSize="12sp"app:textcolor="#E72803" /></LinearLayout></LinearLayout>
只加了一个自定义控件,app:direction=”left” 表示向左滚动,根据自己的需求设定方向;app:isRepeat=”true” 是否重复滚动;app:speed=”100” 设置滚动的速度,值越小速度越快,值越大速度越慢,app:startPoint=”end” 是文字的起始点。
经亲自测试:该自定义控件只能再layout里面使用一次,不可重复使用多个。
然后再MainActivity里面设置开始滚动就OK了,还是把代码贴出来吧!
package com.lai.marqueedemo;import android.os.Bundle;import android.support.v7.app.AppCompatActivity;import com.dalong.marqueeview.MarqueeView;public class MainActivity extends AppCompatActivity {@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);MarqueeView marqueeView = (MarqueeView)findViewById(R.id.tv_marquee);marqueeView.setFocusable(true);marqueeView.requestFocus();marqueeView.setText("我使劲跑");//设置文本marqueeView.startScroll(); //开始}}
这样使用起来就方便了,一起看下其效果:
源码下载地址
如果觉得《Android——TextView实现真正的跑马灯效果》对你有帮助,请点赞、收藏,并留下你的观点哦!