本文实例为大家分享了Android实现文字动态高亮读取进度的具体代码,供大家参考,具体内容如下
类似歌词的效果。播放下面文字的音频,同时音频播放的进度和文字高亮进度保持一致。
简单的类图:
ISubtitleView接口代码如下:
/** * 简要功能描述 ** <详细功能描述> * * @author : liuxs * @date : 2021/3/18 */ public interface ISubtitleView { /** * 获取当前的带时间文字歌词实体类 * @return */ List
getSubtitleItemList(); /** * 设置带时间文字歌词实体类 * @param linesTextList */ void setSubtitleItemList(List linesTextList); /** * just like {@link #setSubtitleItemList(List)} , only call one of them * @param duration */ void setDuration(long duration); /** * 更新pts会刷新文字进度 * @param pts */ void updatePts(long pts); /** * 复位 */ void reset(); } EMSubtitleView类的代码如下: /** * 歌词文字效果的基础view * * <详细功能描述> * * @author : liuxs * @date : 2021/3/17 */ public class EMSubtitleView extends android.support.v7.widget.AppCompatTextView implements ISubtitleView{ private int mMeasuredWidth; private int mMeasuredHeight; private List
mSubtitleItemList; private List mLinesTextList; private Paint mNormalPaint; private Paint mHLPaint; private long mPts = 0; private int mCurHLLine; private float mReadSubtitleCount; private Rect mLastHLRect; private int mHLTextColor; private long mDuration; private boolean mIsPlain = false; public EMSubtitleView(Context context) { this(context , null); } public EMSubtitleView(Context context, AttributeSet attrs) { this(context, attrs , 0); } public EMSubtitleView(Context context, AttributeSet attrs, int defStyleAttr) { super(context, attrs, defStyleAttr); mSubtitleItemList = new ArrayList<>(); mLinesTextList = null; mLastHLRect = new Rect(); mNormalPaint = null; initAttrs(attrs , defStyleAttr); } private void initAttrs(AttributeSet attrs , int defStyleAttr) { TypedArray ta = getContext().obtainStyledAttributes(attrs , R.styleable.EMSubtitleView , defStyleAttr , R.style.EMSubtitleViewDefaultTheme); for(int i = 0 ; i = 0){ int curLineTextCount = 0; for(int i = 0 ; i i){ canvas.drawText( entity.lineText , entity.left , entity.baseLine , mHLPaint); }else if(mCurHLLine == i && mReadSubtitleCount > 0 ){ canvas.save(); mLastHLRect.set(entity.left , entity.top , entity.left + (int) (mHLPaint.measureText(entity.lineText)*1.0f/entity.lineText.length()*(mReadSubtitleCount-curLineTextCount)), entity.bottom); canvas.clipRect(mLastHLRect ); canvas.drawText( entity.lineText , entity.left , entity.baseLine , mHLPaint); canvas.restore(); //遮挡的话需要滚动 if(entity.baseLine > getHeight()){ if(getScrollY() != entity.bottom - getHeight() + 1){ setScrollY( entity.bottom - getHeight() + 1/*- pts/40000 * mMeasuredHeight*/); } } break; } curLineTextCount += entity.lineText.length(); } } } private void calculateReadLineAndWordsCount() { float curSubtitleCount = 0; for(SubtitleItem subtitleItem : mSubtitleItemList){ //文字之间不可以有空隙,否则mCurHLLine可能一直为-1; if(mPts >= subtitleItem.getStartTime() && mPts curSubtitleCount){ mCurHLLine = i; break; } } break; } curSubtitleCount += subtitleItem.getWords().length(); } mReadSubtitleCount = curSubtitleCount; } private void fillLinesEntityListJustOnce() { if(mLinesTextList != null){ return; } mLinesTextList = new ArrayList<>(); Layout layout = getLayout(); int line=getLayout().getLineCount(); String text=layout.getText().toString(); for(int i=0;i getSubtitleItemList() { return mSubtitleItemList; } /** * 设置带时间文字歌词实体类 * @param linesTextList */ public void setSubtitleItemList(List linesTextList) { if(mSubtitleItemList != null){ mSubtitleItemList.clear(); mSubtitleItemList.addAll(linesTextList); }else{ this.mSubtitleItemList = linesTextList; } } /** * must first call setText,then call here * @param duration */ public void setDuration(long duration){ setDuration( duration , false); } private void setDuration(long duration , boolean force){ if((duration > 0 && mDuration != duration) || force){ mDuration = duration; if(mSubtitleItemList != null){ mSubtitleItemList.clear(); }else{ this.mSubtitleItemList = new ArrayList<>(); } mSubtitleItemList.add(new SubtitleItem(getText().toString() , 0 , duration)); } } /** * 更新pts会刷新文字进度 * @param pts */ public void updatePts(long pts){ mPts = pts; postInvalidate(); } /** * 复位 */ public void reset(){ mPts = 0; mCurHLLine = 0; mReadSubtitleCount = 0; mLinesTextList = null; mNormalPaint = null; setScrollY(0); postInvalidate(); } static class LineEntity{ String lineText; int top; int bottom; int ascent; int descent; int baseLine; int left; public LineEntity(String lineText, int top, int bottom, int ascent, int descent, int baseLine, int left) { this.lineText = lineText; this.top = top; this.bottom = bottom; this.ascent = ascent; this.descent = descent; this.baseLine = baseLine; this.left = left; } } }
布局文件里使用类似如下:
处理过程中文字位置的参数需要注意:
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持。