Android——TextView实现真正的跑马灯效果
2016-05-16 10:57
573 查看
android 应用有时候需要做一个广告栏,可以做文字闪烁,跑马灯等效果,文字闪烁可以放在线程里面执行,多少秒过后设置文字的TextColor即可,跑马灯效果很少接触,之前写了一个demo,但是实现的效果不是自己想要的,普遍的跑马灯效果直接在layout里面的TextView控件加上如下属性即可实现:
但是这种效果有一个致命的问题,文字的宽度必须要大于TextView设置的宽度(android:layout_width=”“),有时候需求文字很少,甚至根本没法实现跑马灯效果,这是让人头疼的事。
当然肯定有解决的办法,第一想到的就是自定义,急需要用的时候,自定义显得太麻烦了,耗时间,这里给大家介绍一个封装好的jar,下面一起来实现这个效果。
先要加入marquee的jar包,在项目的build.gradle文件中加入
这里面只有一个类,自定义的MarqueeView,简单的来看一下:
以上代码写明了注释,就不多说了,大家可以了解下。
下面先写一个xml布局文件:
只加了一个自定义控件,app:direction=”left” 表示向左滚动,根据自己的需求设定方向;app:isRepeat=”true” 是否重复滚动;app:speed=”100” 设置滚动的速度,值越小速度越快,值越大速度越慢,app:startPoint=”end” 是文字的起始点。
经亲自测试:该自定义控件只能再layout里面使用一次,不可重复使用多个。
然后再MainActivity里面设置开始滚动就OK了,还是把代码贴出来吧!
这样使用起来就方便了,一起看下其效果:
源码下载地址
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; else currentX=width-getPaddingLeft()-getPaddingRight(); } @Override public void surfaceCreated(SurfaceHolder holder) { this.holder=holder; } @Override public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) { if(mThread!=null) mThread.isRun = true; } @Override public 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(); } } @Override public void run() { while (isRun) { onDraw(); } } } public static final int ROLL_OVER =100; Handler mHandler=new Handler(){ @Override public 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; else currentX=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="http://schemas.android.com/apk/res/android" xmlns:app="http://schemas.android.com/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 { @Override protected 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 canvas layer (图层)详解与进阶
- Android中Fragment切换时重叠透明问题总结
- Mac环境使用Android Studio进行android手机调试
- Android Intent.FLAG_NEW_TASK详解,包括其他的标记的一些解释
- xmarin.android 城市天气预报
- android 5.0之后设置各个区域的颜色
- Android签名证书的sha1值获取方式(使用keytool )
- Android SDK Manager无法安装package,提示:Download interrupted: URL not found.
- Android将程序崩溃信息保存到本地文件
- Android Studio 编译时卡死解决方法
- Androidstudio中gradle配置和使用
- Android将应用log信息保存到文件
- Android - 解决国内不能从google代理服务器更新下载问题
- Android 状态栏变色
- 解决android 在代码中设置view背景后,padding效果消失的bug
- Android编程之SparseArray<E>详解
- Android gson解析json数据工具类
- Android Studio “Cannot resolve symbol” 解决办法
- 15 个 Android 通用流行框架大全
- 解决Xamarin Android墙的问题