最近项目需求做个循环滚动字幕功能,自己找了相关资料,根据自己的风格用两种方法实现了该功能;
(备注:本人只实现了滚动效果,对于文字的格式排版没做处理,格式可能会乱,文字排版还在研究中)
效果图:
具体如下;
方法一:横向滚动字幕继承TextView
package com.example.playpic; import com.example.playpic.AutoScrollTextView.SavedState; import android.content.Context; import android.graphics.Canvas; import android.graphics.Color; import android.graphics.Paint; import android.graphics.Typeface; import android.graphics.Paint.FontMetrics; import android.os.Parcel; import android.os.Parcelable; import android.util.AttributeSet; import android.util.DisplayMetrics; import android.util.Log; import android.view.WindowManager; import android.view.View.BaseSavedState; import android.widget.TextView; public class AutoText extends TextView { private int width,height; private Paint paintText; private float posx,posy; private float speed=0.0f; private String text="hello haha"; private float textWidth=0; private float moveDistance=0.0f; private boolean isStarting=false; public AutoText(Context context) { super(context); } public AutoText(Context context, AttributeSet attrs) { super(context, attrs); } private void initView(){ paintText=new Paint(); paintText.setTextSize(50.0f); paintText.setColor(Color.BLACK); paintText.setTypeface(Typeface.DEFAULT_BOLD); paintText.setAntiAlias(true); text=getText().toString(); textWidth=paintText.measureText(text);Log.e("msg", "textWidth= "+textWidth); this.speed=textWidth; moveDistance=textWidth*2+width; } public void initDisplayMetrics(WindowManager windowManager){ /* 取得屏幕分辨率大小 */ DisplayMetrics dm=new DisplayMetrics(); windowManager.getDefaultDisplay().getMetrics(dm); this.width=dm.widthPixels; this.height=dm.heightPixels; initView(); this.posx=width+textWidth; FontMetrics fm = paintText.getFontMetrics(); float baseline = fm.descent - fm.ascent; this.posy=height/2-baseline; } public void startScroll() { isStarting = true; invalidate(); } public void stopScroll() { isStarting = false; invalidate(); } @Override protected void onDraw(Canvas canvas) { // super.onDraw(canvas); canvas.drawText(text, posx-speed, posy, paintText); if (!isStarting) { return; } speed += 2.0f; if (speed > moveDistance) speed = textWidth; invalidate(); } }
<?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical" > <com.example.playpic.AutoText android:id="@+id/autoTxt" android:layout_width="match_parent" android:layout_height="wrap_content" android:background="#ffffff" android:textColor="#00ff00" android:textSize="35sp" /> </LinearLayout>
package com.example.playpic; import java.util.ArrayList; import java.util.List; import android.content.Context; import android.graphics.Canvas; import android.graphics.Color; import android.graphics.Paint; import android.graphics.Paint.FontMetrics; import android.graphics.Rect; import android.graphics.Typeface; import android.util.AttributeSet; import android.util.DisplayMetrics; import android.view.SurfaceHolder; import android.view.SurfaceView; import android.view.WindowManager; public class ScrollText extends SurfaceView implements SurfaceHolder.Callback ,Runnable{ private int width,height; private SurfaceHolder sfh; private Thread th; private boolean flag; private Paint backPaint,textPaint; /**文字开始出现的位置坐标*/ private float posx,posy; /**每行文本 当前移动文本距离以及文本的原始移动位置*/ private Float[] step,stepBack; private String txtContent; /**存储每行文本原始纵坐标位置*/ private Float[] tposy; /**存储每行文本内容*/ private String[] texts; public ScrollText(Context context) { super(context); initView(); } public ScrollText(Context context, AttributeSet attrs) { super(context, attrs); initView(); } private void initView(){ sfh=this.getHolder(); sfh.addCallback(this); this.setKeepScreenOn(true); this.setFocusable(true); // this.setFocusableInTouchMode(true); backPaint=new Paint(); backPaint.setColor(Color.BLACK); textPaint=new Paint(); textPaint.setTextSize(30.0f); textPaint.setColor(Color.BLUE); textPaint.setTypeface(Typeface.DEFAULT_BOLD); textPaint.setTextAlign(Paint.Align.LEFT); textPaint.setAntiAlias(true); } public void initDisplayMetrics(WindowManager windowManager){ /* 取得屏幕分辨率大小 */ DisplayMetrics dm=new DisplayMetrics(); windowManager.getDefaultDisplay().getMetrics(dm); this.width=dm.widthPixels; this.height=dm.heightPixels; this.posx=width/6; /* FontMetrics fm = textPaint.getFontMetrics(); float baseline = fm.descent - fm.ascent;*/ this.posy=height-100; } public void setTxtContent(String txt){ this.txtContent=txt; } @Override public void surfaceCreated(SurfaceHolder holder) { this.flag=true; if(th==null||!th.isAlive()){ th=new Thread(this); th.start(); } } @Override public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) { } @Override public void surfaceDestroyed(SurfaceHolder holder) { this.flag=false; } /** * 调用所有绘制方法 */ private void drawAll(){ Canvas canvas=null; try{ canvas=sfh.lockCanvas(); drawText(canvas, txtContent); }catch(Exception e){ e.printStackTrace(); }finally{ if(canvas!=null){ sfh.unlockCanvasAndPost(canvas); } } } private void drawText(Canvas canvas,String text){ //clear screen canvas.drawRect(new Rect(0,0,getWidth(),getHeight()), backPaint); initDrawText(text); int len=tposy.length; // draw text content for(int n=0;n<len;n++){ if(texts[n]==null) return; float ty=tposy[n]-step[n]; canvas.drawText(texts[n], posx, ty, textPaint); step[n]+=5.0f; if(n==len-1&&ty<0){ step=stepBack.clone(); } /*if (ty<0){ Log.e("msgreset", "back step"); step[n] = stepBack[n].floatValue(); }*/ } postInvalidate(); } /** * 在文字信息绘制前对文本信息进行文字分割,文字间距,文字位置计算处理 * @param text */ private void initDrawText(String text){ if(texts==null){ texts=getTexts(text); } if(tposy==null){ tposy=getTextLinePosy(); } if(stepBack==null){ stepBack=new Float[tposy.length]; int i=0; float interval=0.0f; FontMetrics fm = textPaint.getFontMetrics(); float baseline = fm.descent - fm.ascent; while(i<stepBack.length){ stepBack[i]=interval; interval-=baseline; i++; } } if(step==null){ step=stepBack.clone(); } } /** * 获取分割后的文本信息 * @param text * @return */ private String[] getTexts(String text){ List<String> totalList=new ArrayList<String>(10); String[] str=text.split("\n"); int len=str.length; for(int i=0;i<len;i++){ String[] ss=autoSplit(str[i], textPaint, getWidth()/3*2); for(String s:ss){ totalList.add(s); } } if(texts==null) texts=(String[]) totalList.toArray(new String[0]); /*if(texts==null) texts = autoSplit(text, textPaint, getWidth()/3*2); */ return texts; } /** * 获取每行文本的纵坐标信息 * @return */ private Float[] getTextLinePosy(){ FontMetrics fm = textPaint.getFontMetrics(); float baseline = fm.descent - fm.ascent; float y = posy+baseline; //由于系统基于字体的底部来绘制文本,所有需要加上字体的高度 int len=texts.length; Float[] groups=new Float[len]; for(int i=0;i<len;i++) { groups[i]=y; y =y+ baseline + fm.leading; //添加字体行间距 } return groups; } /** * 自动分割文本 * @param content 需要分割的文本 * @param p 画笔,用来根据字体测量文本的宽度 * @param width 最大的可显示像素(一般为控件的宽度) * @return 一个字符串数组,保存每行的文本 */ private String[] autoSplit(String content, Paint p, float width) { /* String[] lineTexts = new String[1000]; int lenStr=0; int lineNum=0,w=0,start=0,end=1,n=0; lenStr=content.length(); for(int j=0;j<lenStr;j++){ char ch=content.charAt(j); String str_ch=String.valueOf(ch); float[] ch_w=new float[1]; p.getTextWidths(str_ch, ch_w); if(str_ch=="\n"){ lineNum++; // start=j+1; end=j+1; w=0; lineTexts[n++] = (String) content.subSequence(start, end); start=end; }else{ w+=(int)(Math.ceil(ch_w[0])); if(w>width){ lineNum++; // start=j; end=j; j--; w=0; lineTexts[n++] = (String) content.subSequence(start, end); start=end; }else{ if(j==(lenStr-1)){ lineNum++; lineTexts[n++] = (String) content.subSequence(start, end); break; } } } } Log.e("msg", "lineNum= "+lineNum);*/ float textWidth = p.measureText(content); if(textWidth <= width) { return new String[]{content}; } int length = content.length(); int start = 0, end = 1, i = 0; int lines = (int) Math.ceil(textWidth / width); //计算行数 String[] lineTexts = new String[lines]; while(start < length) { if(p.measureText(content, start, end) > width) { //文本宽度超出控件宽度时 lineTexts[i++] = content.substring(start, end);//(String) content.subSequence(start, end); start = end; } if(end == length) { //不足一行的文本 lineTexts[i] = content.substring(start, end);//(String) content.subSequence(start, end); break; } end += 1; } return lineTexts; } @Override public void run() { while(flag){ drawAll(); try { Thread.sleep(200); } catch (InterruptedException e) { e.printStackTrace(); } } } }
package com.example.playpic; import java.io.BufferedReader; import java.io.File; import java.io.FileInputStream; import java.io.FileNotFoundException; import java.io.FileOutputStream; import java.io.FileReader; import java.io.IOException; import java.io.InputStreamReader; import android.app.Activity; import android.os.Bundle; import android.os.Environment; import android.text.method.ScrollingMovementMethod; import android.util.Log; import android.widget.TextView; import com.sample.fun.R; public class ScrollTextActivity extends Activity{ String str=""; String str11="促进青年教师全面发展,\n引导广大高校青年教师为实现中华民族伟大复兴的中国梦贡献力" +"\n"+"促进青年教师全面发展,\n引导广大高校青年教师为实现中华民族伟大复兴的中国梦贡献力"+"\n"+ " djsdnh kshdfjks \n\r\t "; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); scroll3(); } void scroll2(){ ScrollText v=new ScrollText(getApplicationContext()); setContentView(v); v.setTxtContent(str11); v.initDisplayMetrics(getWindowManager()); } void scroll3(){ setContentView(R.layout.scrollview1); AutoText auto=(AutoText)findViewById(R.id.autoTxt); auto.setText(str11); auto.initDisplayMetrics(getWindowManager()); auto.startScroll(); } }