我的编程空间,编程开发者的网络收藏夹
学习永远不晚

Android如何实现文字动态高亮读取进度效果

短信预约 -IT技能 免费直播动态提醒
省份

北京

  • 北京
  • 上海
  • 天津
  • 重庆
  • 河北
  • 山东
  • 辽宁
  • 黑龙江
  • 吉林
  • 甘肃
  • 青海
  • 河南
  • 江苏
  • 湖北
  • 湖南
  • 江西
  • 浙江
  • 广东
  • 云南
  • 福建
  • 海南
  • 山西
  • 四川
  • 陕西
  • 贵州
  • 安徽
  • 广西
  • 内蒙
  • 西藏
  • 新疆
  • 宁夏
  • 兵团
手机号立即预约

请填写图片验证码后获取短信验证码

看不清楚,换张图片

免费获取短信验证码

Android如何实现文字动态高亮读取进度效果

小编给大家分享一下Android如何实现文字动态高亮读取进度效果,希望大家阅读完这篇文章之后都有所收获,下面让我们一起去探讨吧!

具体内容如下

1、效果图

类似歌词的效果。播放下面文字的音频,同时音频播放的进度和文字高亮进度保持一致。

Android如何实现文字动态高亮读取进度效果

2、代码结构和实现

简单的类图:

Android如何实现文字动态高亮读取进度效果

ISubtitleView接口代码如下:

public interface ISubtitleView {        List<SubtitleItem> getSubtitleItemList();        void setSubtitleItemList(List<SubtitleItem> linesTextList);        void setDuration(long duration);        void updatePts(long pts);        void reset();}EMSubtitleView类的代码如下: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());    }        public void setRichText(String text){        mIsPlain = false;        reset();        setText(text);        setDuration(mDuration , true);    }        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();        }        //没有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();                    //遮挡的话需要滚动                    if(entity.baseLine > getHeight()){                        if(getScrollY() != entity.bottom - getHeight() + 1){                            setScrollY( entity.bottom - getHeight() + 1);                        }                    }                    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;    }        public void setSubtitleItemList(List<SubtitleItem> linesTextList) {        if(mSubtitleItemList != null){            mSubtitleItemList.clear();            mSubtitleItemList.addAll(linesTextList);        }else{            this.mSubtitleItemList = linesTextList;        }    }        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));        }    }        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;        }    }}

布局文件里使用类似如下:

<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、其它

处理过程中文字位置的参数需要注意:

Android如何实现文字动态高亮读取进度效果

Android是什么

Android是一种基于Linux内核的自由及开放源代码的操作系统,主要使用于移动设备,如智能手机和平板电脑,由美国Google公司和开放手机联盟领导及开发。

看完了这篇文章,相信你对“Android如何实现文字动态高亮读取进度效果”有了一定的了解,如果想了解更多相关知识,欢迎关注编程网行业资讯频道,感谢各位的阅读!

免责声明:

① 本站未注明“稿件来源”的信息均来自网络整理。其文字、图片和音视频稿件的所属权归原作者所有。本站收集整理出于非商业性的教育和科研之目的,并不意味着本站赞同其观点或证实其内容的真实性。仅作为临时的测试数据,供内部测试之用。本站并未授权任何人以任何方式主动获取本站任何信息。

② 本站未注明“稿件来源”的临时测试数据将在测试完成后最终做删除处理。有问题或投稿请发送至: 邮箱/279061341@qq.com QQ/279061341

Android如何实现文字动态高亮读取进度效果

下载Word文档到电脑,方便收藏和打印~

下载Word文档

猜你喜欢

Android如何实现文字动态高亮读取进度效果

小编给大家分享一下Android如何实现文字动态高亮读取进度效果,希望大家阅读完这篇文章之后都有所收获,下面让我们一起去探讨吧!具体内容如下1、效果图类似歌词的效果。播放下面文字的音频,同时音频播放的进度和文字高亮进度保持一致。2、代码结构
2023-06-15

Flutter如何实现文本滚动高亮效果

这篇文章主要介绍“Flutter如何实现文本滚动高亮效果”的相关知识,小编通过实际案例向大家展示操作过程,操作方法简单快捷,实用性强,希望这篇“Flutter如何实现文本滚动高亮效果”文章能帮助大家解决问题。功能实现因为在Text中会存在两
2023-06-29

如何利用css3实现进度条效果及动态添加百分比

这篇文章主要介绍了如何利用css3实现进度条效果及动态添加百分比,具有一定借鉴价值,感兴趣的朋友可以参考下,希望大家阅读完这篇文章之后大有收获,下面让小编带着大家一起了解一下。代码:2023-06-08

CSS3怎么实现歌词进度文字颜色填充变化动态效果的思路

这篇文章将为大家详细讲解有关CSS3怎么实现歌词进度文字颜色填充变化动态效果的思路,小编觉得挺实用的,因此分享给大家做个参考,希望大家阅读完这篇文章后可以有所收获。播放音乐时,歌词会随歌曲的进度逐渐填充颜色,不是逐字改变颜色,而是从左向右横
2023-06-08

Android编程如何实现类似天气预报图文字幕垂直滚动效果

小编给大家分享一下Android编程如何实现类似天气预报图文字幕垂直滚动效果,希望大家阅读完这篇文章之后都有所收获,下面让我们一起去探讨吧!在很多天气或者新闻的应用中,我们都能看到一些字幕滚动的效果,最简单的实现为跑马灯效果,用系统提供的属
2023-05-30

编程热搜

  • Python 学习之路 - Python
    一、安装Python34Windows在Python官网(https://www.python.org/downloads/)下载安装包并安装。Python的默认安装路径是:C:\Python34配置环境变量:【右键计算机】--》【属性】-
    Python 学习之路 - Python
  • chatgpt的中文全称是什么
    chatgpt的中文全称是生成型预训练变换模型。ChatGPT是什么ChatGPT是美国人工智能研究实验室OpenAI开发的一种全新聊天机器人模型,它能够通过学习和理解人类的语言来进行对话,还能根据聊天的上下文进行互动,并协助人类完成一系列
    chatgpt的中文全称是什么
  • C/C++中extern函数使用详解
  • C/C++可变参数的使用
    可变参数的使用方法远远不止以下几种,不过在C,C++中使用可变参数时要小心,在使用printf()等函数时传入的参数个数一定不能比前面的格式化字符串中的’%’符号个数少,否则会产生访问越界,运气不好的话还会导致程序崩溃
    C/C++可变参数的使用
  • css样式文件该放在哪里
  • php中数组下标必须是连续的吗
  • Python 3 教程
    Python 3 教程 Python 的 3.0 版本,常被称为 Python 3000,或简称 Py3k。相对于 Python 的早期版本,这是一个较大的升级。为了不带入过多的累赘,Python 3.0 在设计的时候没有考虑向下兼容。 Python
    Python 3 教程
  • Python pip包管理
    一、前言    在Python中, 安装第三方模块是通过 setuptools 这个工具完成的。 Python有两个封装了 setuptools的包管理工具: easy_install  和  pip , 目前官方推荐使用 pip。    
    Python pip包管理
  • ubuntu如何重新编译内核
  • 改善Java代码之慎用java动态编译

目录