最近项目需求做个循环滚动字幕功能,自己找了相关资料,根据自己的风格用两种方法实现了该功能;
(备注:本人只实现了滚动效果,对于文字的格式排版没做处理,格式可能会乱,文字排版还在研究中)
效果图:
具体如下;
方法一:横向滚动字幕继承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();
}
}