1. 程式人生 > >Android 滾動字幕實現

Android 滾動字幕實現

最近專案需求做個迴圈滾動字幕功能,自己找了相關資料,根據自己的風格用兩種方法實現了該功能;

(備註:本人只實現了滾動效果,對於文字的格式排版沒做處理,格式可能會亂,文字排版還在研究中)

效果圖:



具體如下;

方法一:橫向滾動字幕繼承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();  
    }  
      
}