Android 滾動字幕實現
阿新 • • 發佈:2019-01-05
最近專案需求做個迴圈滾動字幕功能,自己找了相關資料,根據自己的風格用兩種方法實現了該功能;
(備註:本人只實現了滾動效果,對於文字的格式排版沒做處理,格式可能會亂,文字排版還在研究中)
效果圖:
具體如下;
方法一:橫向滾動字幕繼承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>
方法二:繼承sufaceView實現縱向文字滾動功能
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();
}
}