Android實現(xiàn)歌詞滑動顯示

繼承TextView自定義LyricView

import java.util.List;  
  
import com.anjoyo.musicplayer.bean.LyricBean;  
  
import android.content.Context;  
import android.graphics.Canvas;  
import android.graphics.Color;  
import android.graphics.LinearGradient;  
import android.graphics.Paint;  
import android.graphics.Shader;  
import android.graphics.Typeface;  
import android.graphics.Paint.Align;  
import android.graphics.Shader.TileMode;  
import android.util.AttributeSet;  
import android.widget.TextView;  
  
public class LyricView extends TextView {  
  
    /** 控件的高 */  
    private float mHeight;  
    /** 控件的寬 */  
    private float mWidth;  
    private Paint mPaint;  
    private Paint prePaint;  
    private Paint nextPaint;  
      
    /** 當(dāng)前歌曲的歌詞 */  
    private List<LyricBean> lyricBeanList;  
    /** 歌詞進度碗硬,List中的位置 */  
    private int index;  
      
    private float heightSign;  
    private boolean start;  
      
    private Shader inShader = new LinearGradient(0, 0, 0, LYRIC_ONE_HEIGHT,   
            Color.argb(0xcc, 0xcc, 0xcc, 0xcc),   
            Color.argb(0xff, 0xff, 0xff, 0xff), TileMode.MIRROR);  
    private Shader outShader = new LinearGradient(0, LYRIC_ONE_HEIGHT, 0, 0,   
            Color.argb(0xcc, 0xcc, 0xcc, 0xcc),   
            Color.argb(0xff, 0xff, 0xff, 0xff), TileMode.MIRROR);  
      
    /** 歌詞顯示的字體大小 */  
    private static final int LYRIC_TEXT_SIZE = 36;  
    /** 每行歌詞的高度 */  
    private static final int LYRIC_ONE_HEIGHT = 60;  
      
    public LyricView(Context context) {  
        super(context);  
        initView();  
    }  
  
    public LyricView(Context context, AttributeSet attrs, int defStyle) {  
        super(context, attrs, defStyle);  
        initView();  
    }  
  
    public LyricView(Context context, AttributeSet attrs) {  
        super(context, attrs);  
        initView();  
          
        new UpdateThread().start();  
    }  
      
    private void initView() {  
        setFocusable(true);  
           
        mPaint = new Paint();  
        mPaint.setAntiAlias(true);// 設(shè)置畫筆的鋸齒效果  
        mPaint.setTextAlign(Align.CENTER);  
        mPaint.setTextSize(LYRIC_TEXT_SIZE);  
        mPaint.setTypeface(Typeface.SERIF);  
          
        prePaint = new Paint(mPaint);  
        prePaint.setShader(outShader);  
        nextPaint = new Paint(mPaint);  
        nextPaint.setShader(inShader);  
    }  
      
    @Override  
    protected void onDraw(Canvas canvas) {  
        super.onDraw(canvas);  
        if (canvas == null) {  
            return;  
        }  
        mPaint.setColor(Color.argb(0xff, 0xff, 0xff, 0xff));//當(dāng)前歌詞詞句顏色  
        if (lyricBeanList == null || lyricBeanList.size() < 1 || index > lyricBeanList.size() - 1) {  
            canvas.drawText("好音質(zhì)恩尾,MusicPlayer惜索!", mWidth / 2, mHeight / 2, mPaint);  
            return;  
        }  
        canvas.drawText(lyricBeanList.get(index).getLyric(), mWidth / 2, heightSign, mPaint);  
          
        mPaint.setColor(Color.argb(0xcc, 0xcc, 0xcc, 0xcc));//非當(dāng)前歌詞詞句顏色  
          
        float currentY = heightSign;  
        //畫出本句之前的歌詞  
        for (int i = index - 1; i >= 0; i--) {  
            currentY -= LYRIC_ONE_HEIGHT;  
            if (i == index - 1) {  
                canvas.drawText(lyricBeanList.get(i).getLyric(), mWidth / 2,  
                        currentY, prePaint);  
            } else {  
                canvas.drawText(lyricBeanList.get(i).getLyric(), mWidth / 2,  
                        currentY, mPaint);  
            }  
        }  
        currentY = heightSign;  
        //畫出本句之后的歌詞  
        for (int i = index + 1; i < lyricBeanList.size(); i++) {  
            currentY += LYRIC_ONE_HEIGHT;  
            if (i == index + 1) {  
                canvas.drawText(lyricBeanList.get(i).getLyric(), mWidth / 2,  
                        currentY, nextPaint);     
            } else {  
                canvas.drawText(lyricBeanList.get(i).getLyric(), mWidth / 2,  
                        currentY, mPaint);        
            }  
        }  
    }  
      
    public void setLyricList(List<LyricBean> lyricBeanList) {  
        this.lyricBeanList = lyricBeanList;  
    }  
      
    public void setStart(boolean start) {  
        this.start = start;  
    }  
      
    public boolean getStart() {  
        return this.start;  
    }  
      
    public void setIndex(int index) {  
        if (this.index != index) {  
            this.index = index;  
            heightSign = mHeight / 2 + LYRIC_ONE_HEIGHT / 2;  
        }  
    }  
      
    private class UpdateThread extends Thread {  
        @Override  
        public void run() {  
            while (true) {  
                if (start && lyricBeanList.size() > index + 1) {  
                    if (heightSign > mHeight / 2f - LYRIC_ONE_HEIGHT / 2f) {  
                        heightSign -= LYRIC_ONE_HEIGHT /   
                                (float)(lyricBeanList.get(index + 1).getLyricTime()   
                                        - lyricBeanList.get(index).getLyricTime()) * 50;  
                    }  
                    postInvalidate();  
                }  
                try {  
                    sleep(50);  
                } catch (InterruptedException e) {  
                    e.printStackTrace();  
                }  
            }  
        }  
    }  
      
    @Override  
    protected void onSizeChanged(int w, int h, int oldw, int oldh) {  
        super.onSizeChanged(w, h, oldw, oldh);  
        mWidth = w;  
        mHeight = h;  
        heightSign = h / 2f + LYRIC_ONE_HEIGHT / 2f;  
    }  
  
      
}

LyricBean.java如下

import java.util.List;  
  
/** 
 * 一句歌詞 
 *  
 * @author HLP 
 */  
public class LyricBean {  
  
    /** 一句歌詞 */  
    private String lyric;  
    /** 本句歌詞開始的時間 */  
    private int lyricTime;  
    /** 本句歌詞每個字的持續(xù)時間 ,構(gòu)成數(shù)組 */  
    private List<Integer> wordsTime;  
  
    public LyricBean(String lyric, int lyricTime, List<Integer> wordsTime) {  
        super();  
        this.lyric = lyric;  
        this.lyricTime = lyricTime;  
        this.wordsTime = wordsTime;  
    }  
  
    public String getLyric() {  
        return lyric;  
    }  
  
    public void setLyric(String lyric) {  
        this.lyric = lyric;  
    }  
  
    public int getLyricTime() {  
        return lyricTime;  
    }  
  
    public void setLyricTime(int lyricTime) {  
        this.lyricTime = lyricTime;  
    }  
  
    public List<Integer> getWordsTime() {  
        return wordsTime;  
    }  
  
    public void setWordsTime(List<Integer> wordsTime) {  
        this.wordsTime = wordsTime;  
    }  
  
}

有個模擬【天天動聽】的項目在GitHub上蔫磨,需要手機中有MP3歌曲和天天動聽格式的歌詞圃伶,
歌曲和歌詞文件名一致,查看請點擊

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市侥猩,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌唧取,老刑警劉巖划提,帶你破解...
    沈念sama閱讀 212,454評論 6 493
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件鹏往,死亡現(xiàn)場離奇詭異伊履,居然都是意外死亡,警方通過查閱死者的電腦和手機湾碎,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,553評論 3 385
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人溢陪,你說我怎么就攤上這事形真。” “怎么了咆霜?”我有些...
    開封第一講書人閱讀 157,921評論 0 348
  • 文/不壞的土叔 我叫張陵蛾坯,是天一觀的道長疏遏。 經(jīng)常有香客問我,道長倘零,這世上最難降的妖魔是什么戳寸? 我笑而不...
    開封第一講書人閱讀 56,648評論 1 284
  • 正文 為了忘掉前任,我火速辦了婚禮俐东,結(jié)果婚禮上虏辫,老公的妹妹穿的比我還像新娘。我一直安慰自己砌庄,他們只是感情好娄昆,可當(dāng)我...
    茶點故事閱讀 65,770評論 6 386
  • 文/花漫 我一把揭開白布萌焰。 她就那樣靜靜地躺著扒俯,像睡著了一般。 火紅的嫁衣襯著肌膚如雪撼玄。 梳的紋絲不亂的頭發(fā)上掌猛,一...
    開封第一講書人閱讀 49,950評論 1 291
  • 那天荔茬,我揣著相機與錄音,去河邊找鬼殖卑。 笑死坊萝,一個胖子當(dāng)著我的面吹牛十偶,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播接校,決...
    沈念sama閱讀 39,090評論 3 410
  • 文/蒼蘭香墨 我猛地睜開眼蛛勉,長吁一口氣:“原來是場噩夢啊……” “哼诽凌!你這毒婦竟也來了坦敌?” 一聲冷哼從身側(cè)響起狱窘,我...
    開封第一講書人閱讀 37,817評論 0 268
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎蘸炸,沒想到半個月后躬络,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 44,275評論 1 303
  • 正文 獨居荒郊野嶺守林人離奇死亡搭儒,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 36,592評論 2 327
  • 正文 我和宋清朗相戀三年洗鸵,在試婚紗的時候發(fā)現(xiàn)自己被綠了越锈。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 38,724評論 1 341
  • 序言:一個原本活蹦亂跳的男人離奇死亡膘滨,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出稀拐,到底是詐尸還是另有隱情火邓,我是刑警寧澤,帶...
    沈念sama閱讀 34,409評論 4 333
  • 正文 年R本政府宣布德撬,位于F島的核電站铲咨,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏蜓洪。R本人自食惡果不足惜隆檀,卻給世界環(huán)境...
    茶點故事閱讀 40,052評論 3 316
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望腕让。 院中可真熱鬧纯丸,春花似錦觉鼻、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,815評論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽萍嬉。三九已至壤追,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間悼做,已是汗流浹背肛走。 一陣腳步聲響...
    開封第一講書人閱讀 32,043評論 1 266
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人腾誉。 一個月前我還...
    沈念sama閱讀 46,503評論 2 361
  • 正文 我出身青樓瘦癌,卻偏偏與公主長得像热押,于是被迫代替她去往敵國和親桶癣。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 43,627評論 2 350

推薦閱讀更多精彩內(nèi)容

  • Android 自定義View的各種姿勢1 Activity的顯示之ViewRootImpl詳解 Activity...
    passiontim閱讀 171,846評論 25 707
  • 人生這條路,真的很長,路途漫漫驳规,總會在旅途中迷茫,不知所措捻勉,方向仿佛失去了踱启,好迷茫,心好累冠蒋,好想好想就這樣不了...
    矜文閱讀 498評論 0 0
  • 今天早上斩郎,墩哥來到教室孽拷,發(fā)現(xiàn)我們班的掃帚又壞了脓恕,而且還是掃帚桿斷了炼幔。一把掃帚肛著,如果掃帚桿斷了枢贿,基本也就再無用武之地...
    凡泛閱讀 330評論 0 2
  • 說實話仙逻,在我的長大成人,開始獨立生活之前喜最,我并沒有特別體會過什么是“窮”。 八十年代的中國虫蝶,改革開放之前,大家的生...
    盧璐說閱讀 5,664評論 43 204
  • 他追我的第六個月了蝙泼,我好像有點動心了汤踏,可是溪胶,動心是單純的一種感動盾饮,這是每個認(rèn)真的人都能給我的工扎,不喜歡卻是確確實實...
    庭院深深a閱讀 195評論 0 0