最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

Android實(shí)現(xiàn)文字動(dòng)態(tài)高亮讀取進(jìn)度效果

 更新時(shí)間:2021年05月21日 09:31:36   作者:weixin_小栓  
這篇文章主要為大家詳細(xì)介紹了Android實(shí)現(xiàn)文字動(dòng)態(tài)高亮讀取進(jìn)度效果,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下

本文實(shí)例為大家分享了Android實(shí)現(xiàn)文字動(dòng)態(tài)高亮讀取進(jìn)度的具體代碼,供大家參考,具體內(nèi)容如下

1、效果圖

類(lèi)似歌詞的效果。播放下面文字的音頻,同時(shí)音頻播放的進(jìn)度和文字高亮進(jìn)度保持一致。

2、代碼結(jié)構(gòu)和實(shí)現(xiàn)

簡(jiǎn)單的類(lèi)圖:

ISubtitleView接口代碼如下:

/**
 * 簡(jiǎn)要功能描述
 * <p>
 * <詳細(xì)功能描述>
 *
 * @author : liuxs
 * @date : 2021/3/18
 */
public interface ISubtitleView {

    /**
     * 獲取當(dāng)前的帶時(shí)間文字歌詞實(shí)體類(lèi)
     * @return
     */
    List<SubtitleItem> getSubtitleItemList();

    /**
     * 設(shè)置帶時(shí)間文字歌詞實(shí)體類(lèi)
     * @param linesTextList
     */
    void setSubtitleItemList(List<SubtitleItem> linesTextList);

    /**
     * just like {@link #setSubtitleItemList(List)} , only call one of them
     * @param duration
     */
    void setDuration(long duration);

    /**
     * 更新pts會(huì)刷新文字進(jìn)度
     * @param pts
     */
    void updatePts(long pts);

    /**
     * 復(fù)位
     */
    void reset();
}
EMSubtitleView類(lèi)的代碼如下:

/**
 * 歌詞文字效果的基礎(chǔ)view
 * <p>
 * <詳細(xì)功能描述>
 *
 * @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<SubtitleItem> mSubtitleItemList;
    private List<LineEntity> 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 < ta.getIndexCount() ; i++){
            int index = ta.getIndex(i);
            if (index == R.styleable.EMSubtitleView_highLightTextColor) {
                mHLTextColor = ta.getColor(index, getResources().getColor(R.color.emvideovisit_color_FF9000));
            }
        }
        ta.recycle();
    }
    private void initHLPaint() {
        mHLPaint = new Paint(mNormalPaint);
        mHLPaint.setColor(mHLTextColor);
        mHLPaint.setTextSize(getTextSize());
    }

    /**
     * 設(shè)置文字
     * 作為可以滾動(dòng)高亮顯示的文本
     * @param text
     */
    public void setRichText(String text){
        mIsPlain = false;
        reset();
        setText(text);
        setDuration(mDuration , true);
    }

    /**
     * 設(shè)置文字
     * 當(dāng)作普通的textView使用
     * @param text
     */
    public void setPlainText(String text){
        mIsPlain = true;
        reset();
        setText(text);
    }

    @Override
    protected void onDraw(Canvas canvas) {
        if (mMeasuredWidth == 0 || mMeasuredHeight == 0) {
            mMeasuredWidth = getMeasuredWidth();
            mMeasuredHeight = getMeasuredHeight();
        }

        if(mIsPlain){
            super.onDraw(canvas);
            return;
        }
        if(mNormalPaint == null){
            super.onDraw(canvas);
            mNormalPaint = getPaint();
            initHLPaint();
            return;
        }

        if(mLinesTextList == null){
            fillLinesEntityListJustOnce();
        }
        //沒(méi)有pts,繪制
        if(mPts <= 0){
            drawNormalText(canvas);
            return;
        }
        drawNormalText(canvas);
        calculateReadLineAndWordsCount();

        //繪制高亮部分歌詞
        drawHLText(canvas);
    }

    private void drawHLText(Canvas canvas) {
        if(mCurHLLine >= 0){
            int curLineTextCount = 0;
            for(int i = 0 ; i < mLinesTextList.size() ; ++i){
                LineEntity entity = mLinesTextList.get(i);
                if(mCurHLLine > 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();
                    //遮擋的話(huà)需要滾動(dòng)
                    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 < subtitleItem.getEndTime()){
                float lineOffset = (subtitleItem.getWords().length()*1.0f/(subtitleItem.getEndTime() - subtitleItem.getStartTime()))*(mPts-subtitleItem.getStartTime());
                curSubtitleCount += lineOffset;
                int curLineTextCount = 0;
                for(int i = 0 ; i < mLinesTextList.size() ; ++i){
                    curLineTextCount += mLinesTextList.get(i).lineText.length();
                    if(curLineTextCount > 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<line;i++){
            int start=layout.getLineStart(i);
            int end=layout.getLineEnd(i);
            int left = (int) layout.getLineLeft(i);
            int baseLine = layout.getLineBaseline(i);
            Paint.FontMetrics fontMetrics = getPaint().getFontMetrics();
            int top = (int) (baseLine + fontMetrics.top);
            int bottom = (int) (baseLine + fontMetrics.bottom);
            int ascent = (int) (baseLine + fontMetrics.ascent);
            int descent = (int) (baseLine + fontMetrics.descent);

            mLinesTextList.add(new LineEntity(text.substring(start, end) , top , bottom , ascent , descent ,baseLine , left));
        }
    }

    private void drawNormalText(Canvas canvas) {
        for(LineEntity entity : mLinesTextList){
            canvas.drawText(entity.lineText, entity.left,  entity.baseLine , mNormalPaint);
        }
    }

    public List<SubtitleItem> getSubtitleItemList() {
        return mSubtitleItemList;
    }

    /**
     * 設(shè)置帶時(shí)間文字歌詞實(shí)體類(lèi)
     * @param linesTextList
     */
    public void setSubtitleItemList(List<SubtitleItem> 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會(huì)刷新文字進(jìn)度
     * @param pts
     */
    public void updatePts(long pts){
        mPts = pts;
        postInvalidate();
    }

    /**
     * 復(fù)位
     */
    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;
        }

    }
}

布局文件里使用類(lèi)似如下:

<com.eastmoney.emvideovisit.view.EMSubtitleView
        android:id="@+id/play_text"
        android:layout_width="match_parent"
        android:layout_height="@dimen/emvideovisit_dp_60"
        android:layout_marginLeft="@dimen/emvideovisit_dp_60"
        android:layout_marginRight="@dimen/emvideovisit_dp_60"
        android:gravity="center_horizontal"
        android:layout_marginTop="@dimen/emvideovisit_dp_20"
        android:textColor="#fff"
        app:highLightTextColor="#A6EA5504"
        android:text="@string/emvideovisit_string_headset_tips"
        android:textSize="@dimen/emvideovisit_dp_16"
        android:layout_marginBottom="@dimen/emvideovisit_dp_4"/>

3、其它

處理過(guò)程中文字位置的參數(shù)需要注意:

以上就是本文的全部?jī)?nèi)容,希望對(duì)大家的學(xué)習(xí)有所幫助,也希望大家多多支持腳本之家。

相關(guān)文章

  • Android 仿淘寶商品屬性標(biāo)簽頁(yè)

    Android 仿淘寶商品屬性標(biāo)簽頁(yè)

    這篇文章主要介紹了Android 仿淘寶商品屬性標(biāo)簽頁(yè)的相關(guān)資料,非常不錯(cuò),具有參考借鑒價(jià)值,需要的朋友可以參考下
    2016-11-11
  • Android模仿實(shí)現(xiàn)微博詳情頁(yè)滑動(dòng)固定頂部欄的效果實(shí)例

    Android模仿實(shí)現(xiàn)微博詳情頁(yè)滑動(dòng)固定頂部欄的效果實(shí)例

    這篇文章主要給大家介紹了關(guān)于利用Android模仿實(shí)現(xiàn)微博詳情頁(yè)滑動(dòng)固定頂部欄效果的相關(guān)資料,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面來(lái)一起學(xué)習(xí)學(xué)習(xí)吧。
    2017-11-11
  • 常見(jiàn)的8個(gè)Android內(nèi)存泄漏問(wèn)題及解決方法

    常見(jiàn)的8個(gè)Android內(nèi)存泄漏問(wèn)題及解決方法

    在Android開(kāi)發(fā)中,內(nèi)存泄漏是一個(gè)常見(jiàn)的問(wèn)題,這個(gè)問(wèn)題可能會(huì)導(dǎo)致應(yīng)用程序變慢、崩潰或者消耗大量的內(nèi)存,最終導(dǎo)致設(shè)備性能下降,本文就給大家總結(jié)一下最常見(jiàn)的8個(gè)Android內(nèi)存泄漏問(wèn)題及解決方法,需要的朋友可以參考下
    2023-07-07
  • Android編程中EditText限制文字輸入的方法

    Android編程中EditText限制文字輸入的方法

    這篇文章主要介紹了Android編程中EditText限制文字輸入的方法,涉及Android針對(duì)EditText的監(jiān)聽(tīng)技巧,具有一定參考借鑒價(jià)值,需要的朋友可以參考下
    2015-11-11
  • Android編程中沉浸式狀態(tài)欄的三種實(shí)現(xiàn)方式詳解

    Android編程中沉浸式狀態(tài)欄的三種實(shí)現(xiàn)方式詳解

    這篇文章主要介紹了Android編程中沉浸式狀態(tài)欄的三種實(shí)現(xiàn)方式,簡(jiǎn)單描述了沉浸式狀態(tài)欄的概念、功能并結(jié)合實(shí)例形式詳細(xì)分析了Android實(shí)現(xiàn)沉浸式狀態(tài)欄的三種操作技巧與注意事項(xiàng),需要的朋友可以參考下
    2018-02-02
  • android仿百度福袋紅包界面

    android仿百度福袋紅包界面

    雙十一馬上到了,又進(jìn)入到搶紅包的季節(jié),本篇文章介紹了android仿百度福袋紅包界面,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下。
    2016-11-11
  • Android中各級(jí)目錄的作用說(shuō)明

    Android中各級(jí)目錄的作用說(shuō)明

    這篇文章主要介紹了Android中各級(jí)目錄的作用,有需要的朋友可以參考一下
    2013-12-12
  • Android?雙屏異顯自適應(yīng)Dialog的實(shí)現(xiàn)

    Android?雙屏異顯自適應(yīng)Dialog的實(shí)現(xiàn)

    Android 多屏互聯(lián)的時(shí)代,必然會(huì)出現(xiàn)多屏連接的問(wèn)題,本文主要介紹了Android?雙屏異顯自適應(yīng)Dialog的實(shí)現(xiàn),具有一定的參考價(jià)值,感興趣的可以了解一下
    2023-12-12
  • Android更多條目收縮展開(kāi)控件ExpandView的示例代碼

    Android更多條目收縮展開(kāi)控件ExpandView的示例代碼

    本篇文章主要介紹了Android更多條目收縮展開(kāi)控件ExpandView的示例代碼,小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧
    2018-01-01
  • Android實(shí)現(xiàn)引導(dǎo)頁(yè)的圓點(diǎn)指示器

    Android實(shí)現(xiàn)引導(dǎo)頁(yè)的圓點(diǎn)指示器

    這篇文章主要為大家詳細(xì)介紹了Android實(shí)現(xiàn)引導(dǎo)頁(yè)的圓點(diǎn)指示器,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2021-06-06

最新評(píng)論

会昌县| 阜康市| 元谋县| 舒城县| 宁陕县| 抚顺市| 玉山县| 桐梓县| 若尔盖县| 鄢陵县| 田阳县| 手机| 霸州市| 临邑县| 枣阳市| 万载县| 钟山县| 浦江县| 云霄县| 广汉市| 墨脱县| 岫岩| 惠水县| 普兰县| 日喀则市| 白银市| 乐东| 洛隆县| 湟中县| 靖安县| 呼伦贝尔市| 朝阳市| 广安市| 嘉荫县| 兴安盟| 万源市| 峨山| 潮安县| 托克逊县| 昌黎县| 长丰县|