1. 程式人生 > >Android自定義View,高仿QQ音樂歌詞滾動控制元件!

Android自定義View,高仿QQ音樂歌詞滾動控制元件!

最近在以QQ音樂為樣板做一個手機音樂播放器,原始碼下篇博文放出。今天我想聊的是這個QQ音樂播放器中歌詞顯示控制元件的問題,和小夥伴們一起來探討怎麼實現這個歌詞滾動的效果。OK,廢話不多說,先來看看效果圖:

好,接下來我們就來看看怎麼實現這樣一個效果。本文主要包括如下幾方面內容:

1.歌詞檔案格式分析及解析

2.歌詞顯示控制元件繪製

3.關於卡拉OK模式

4.使用方式

好,那就開始吧。

1.歌詞檔案格式分析及解析

首先,小夥伴們需要明白歌詞檔案的格式都是固定的,是什麼樣子的呢,我們來看看下圖:

我們一個歌詞檔案開啟都是這種格式,前面  []  中的是該行歌詞顯示的時間,後面一行是歌詞,只有時間沒有歌詞的行就是伴奏時間。瞭解了這固定的歌詞格式,剩下的就簡單了,解析這段文字就行了。我建立一個LrcBean用來存放每一行的資料,這個LrcBean中包括三個屬性,分別是一句歌詞,該歌詞開始唱的時間,該歌詞唱完的時間,咦,有的小夥伴可能有疑問,唱完是什麼時候呢?就是下一句的開始時間唄。OK,那我們來看看實體類:

public class LrcBean {
    private String lrc;
    private long start;
    private long end;

    public LrcBean() {
    }

    public LrcBean(String text, long start, long end) {
        this.lrc = text;
        this.start = start;
        this.end = end;
    }

    public String getLrc() {
        return lrc;
    }

    public void setLrc(String lrc) {
        this.lrc = lrc;
    }

    public long getStart() {
        return start;
    }

    public void setStart(long start) {
        this.start = start;
    }

    public long getEnd() {
        return end;
    }

    public void setEnd(long end) {
        this.end = end;
    }
}

OK,實體類有了,接下來我們來看看實體類怎麼解析歌詞文字,解析過程分為兩步:

1.考慮到歌詞文字中可能有轉義字元,我們需要先把轉義字元還原

2.然後按照換行符將文字拆分,再通過字串擷取將每一行的資料提取出來。程式碼如下(由於轉義字元顯示不出來,所以我這裡貼一張程式碼圖,原始碼文末可以下載):


OK,通過以上方式我們就把歌詞檔案解析成了一個List集合,該集合中的每一項就是一句歌詞,另外,在伴奏的時間段,我顯示一句music。

2.歌詞顯示控制元件繪製

歌詞解析完了,接下來我們就可以繪製歌詞View了。繪製的整體思路是這樣:

1.首先獲取當前播放的時間

2.根據當前播放時間,遍歷歌詞的List集合,判斷出當前正在播放的是List集合中的哪一句,找到該句的下標

3.遍歷歌詞List集合,繪製所有歌詞,繪製的過程中,如果該句是正在播放的歌詞,則使用高亮的畫筆來繪製,否則使用普通畫筆繪製。

4.判斷當前是否已經換行了,如果是,則呼叫setScrollY方法讓螢幕滾動一行。關於setScrollY方法如果小夥伴們還不太瞭解可以參考這篇文章View繪製詳解(五),draw方法細節詳解之View的滾動/滑動問題

5.每隔100毫秒重繪View。

OK,整個流程就是這樣,接下來我們來看看程式碼實現:

    @Override
    protected void onDraw(Canvas canvas) {
        if (width == 0 || height == 0) {
            width = getMeasuredWidth();
            height = getMeasuredHeight();
        }
        if (list == null || list.size() == 0) {
            canvas.drawText("暫無歌詞", width / 2, height / 2, gPaint);
            return;
        }

        getCurrentPosition();

        int currentMillis = player.getCurrentPosition();
        drawLrc2(canvas);
        long start = list.get(currentPosition).getStart();
        float v = (currentMillis - start) > 500 ? currentPosition * 80 : lastPosition * 80 + (currentPosition - lastPosition) * 80 * ((currentMillis - start) / 500f);
        setScrollY((int) v);
        if (getScrollY() == currentPosition * 80) {
            lastPosition = currentPosition;
        }
        postInvalidateDelayed(100);
    }

    private void drawLrc2(Canvas canvas) {
        for (int i = 0; i < list.size(); i++) {
            if (i == currentPosition) {
                canvas.drawText(list.get(i).getText(), width / 2, height / 2 + 80 * i, hPaint);
            } else {
                canvas.drawText(list.get(i).getText(), width / 2, height / 2 + 80 * i, gPaint);
            }
        }
    }

    private void getCurrentPosition() {
        try {
            int currentMillis = player.getCurrentPosition();
            if (currentMillis < list.get(0).getStart()) {
                currentPosition = 0;
                return;
            }
            if (currentMillis > list.get(list.size() - 1).getStart()) {
                currentPosition = list.size() - 1;
                return;
            }
            for (int i = 0; i < list.size(); i++) {
                if (currentMillis >= list.get(i).getStart() && currentMillis < list.get(i).getEnd()) {
                    currentPosition = i;
                    return;
                }
            }
        } catch (Exception e) {
//            e.printStackTrace();
            postInvalidateDelayed(100);
        }
    }

OK,這裡給出一個核心程式碼,完整程式碼小夥伴們在文末可以自行下載。

3.關於卡拉OK模式

OK,經過第二個步驟之後,我們這個歌詞控制元件已經可以根據當前播放的時間來顯示高亮的歌詞,同時進行歌詞的滾動。有的小夥伴可能還想實現一種類似於KTV裡邊的那種播放效果,我們也來看一看怎麼實現。還是先來說說思路吧。

1.把所有的歌詞都用普通的畫筆畫出來

2.為當前正在播放的歌詞生成一個Bitmap

3.根據當前播放時間,計算出該句歌詞播放的比例,然後根據這個比例繪製第二步生成的Bitmap。

OK,根據上述的思路,我貼出核心程式碼如下:

for (int i = 0; i < list.size(); i++) {
                canvas.drawText(list.get(i).getLrc(), width / 2, height / 2 + 80 * i, gPaint);
            }
            String highLineLrc = list.get(currentPosition).getLrc();
            int highLineWidth = (int) gPaint.measureText(highLineLrc);
            int leftOffset = (width - highLineWidth) / 2;
            LrcBean lrcBean = list.get(currentPosition);
            long start = lrcBean.getStart();
            long end = lrcBean.getEnd();
            int i = (int) ((currentMillis - start) * 1.0f / (end - start) * highLineWidth);
            if (i > 0) {
                Bitmap textBitmap = Bitmap.createBitmap(i, 80, Bitmap.Config.ARGB_8888);
                Canvas textCanvas = new Canvas(textBitmap);
                textCanvas.drawText(highLineLrc, highLineWidth / 2, 80, hPaint);
                canvas.drawBitmap(textBitmap, leftOffset, height / 2 + 80 * (currentPosition - 1), null);
            }

4.使用方式

OK,控制元件做好了,最後我們再來看看使用方式。很簡單,引入這個View 的類庫(文末會給出下載地址),然後傳入歌詞的文字,開啟繪製即可,如下:

lrcView.setLrc(lrcStr);
        lrcView.setPlayer(PlayUtil.player);
        lrcView.init();

簡單三行程式碼,就可以開始使用了。

相關推薦

Android定義View仿QQ音樂歌詞滾動控制元件

最近在以QQ音樂為樣板做一個手機音樂播放器,原始碼下篇博文放出。今天我想聊的是這個QQ音樂播放器中歌詞顯示控制元件的問題,和小夥伴們一起來探討怎麼實現這個歌詞滾動的效果。OK,廢話不多說,先來看看效果圖:好,接下來我們就來看看怎麼實現這樣一個效果。本文主要包括如下幾方面內容:

android 定義view在xml中引用內部類View

java.lang.ClassCastException: android.view.View cannot be cast to com.voice.VoiceFragment$AnimationView E/AndroidRuntime( 3543): at com.voice.VoiceFragme

Android定義view之實現仿抖音雙擊點贊單擊暫停特效

       2018年抖音、快手、火山等短視訊App比較火,最近自己做短視訊專案時有個需求,就是類似抖音的點贊特效,單擊螢幕時視訊暫停,再次點選時視訊恢復播放,雙擊或者連續多次點選時出現點贊特效(飄小心心特效),而且是全屏可以隨意點選,都

Android 定義View虛線縱向、橫向

虛線在shape中配置還是比較麻煩的,所以自定義一個,使用起來會方便很多。  虛線支援橫向、縱向兩種方式。並且高寬間隔都可以自定義,使用很靈活。 使用說明: 預設方向:橫向。 橫向時:預設寬度為40,預設高度為View高度 縱向時:預設寬度為View的寬度,預設

Android 定義View實現折線圖

最近要完成一個折線圖控制元件,用來顯示一系列的狀態,並可以進行滑動。雖然現在有很多大牛寫好的控制元件可以直接使用,但我感覺那些控制元件是給高手的使用的,對於我這樣的菜鳥,還是腳踏實地,自己慢慢碼程式碼,才可以提高。下面就是結果圖(每種狀態用一個表情圖片表示): 1 主頁

Android定義View實現全屏滑動的DrawerLayout

    對與DrawerLayout大家應該用過,是Google官方推出的一種抽屜式導航控制元件。開啟左右兩邊選單的方式是從手機屏 幕的邊緣處滑動來觸發,不過總有些**的需求要讓它可以全屏滑動觸發選單,網上也有一些解決辦法,無非就是用 setDrawerLeftE

Android定義View畫一個好看帶延長線的餅狀圖

開發十年,就只剩下這套架構體系了! >>>   

android定義View仿通訊錄側邊欄滑動實現A-Z字母檢索

我們的手機通訊錄一般都有這樣的效果,如下圖: OK,這種效果大家都見得多了,基本上所有的android手機通訊錄都有這樣的效果。那我們今天就來看看這個效果該怎麼實現。 一.概述 1.頁面功能分析 整體上來說,左邊是一個ListView,右邊是一個自定義View,但

Android 仿微信聯絡人Demo(定義ViewViewgroup)

上週在某部落格發現博主分享了一篇很經典的程式---------聯絡人效果。感覺很神祕很強大,但在閱讀和理解博主的demo的同時也發現了一些冗餘和不完美。於是帶著寶寶的痛一咬牙自己開工了,大約花了一週的時間(當然我白天還得上班的),做出了這種效果。如下圖: now跟著

Android定義View仿QQ側滑選單實現

最近,由於正在做的一個應用中要用到側滑選單,所以通過查資料看視訊,學習了一下自定義View,實現一個類似於QQ的側滑選單,順便還將其封裝為自定義元件,可以實現類似QQ的側滑選單和抽屜式側滑選單兩種選單。 下面先放上效果圖: 我們這裡的側

實現定義view(2):仿Android QQ多螢幕顯示ListView的效果

本文在《仿 UC,墨跡天氣左右拖動 多螢幕顯示效果》的基礎上對程式碼進行修改,模仿Android QQ主介面的分屏ListView滑動效果。 當進行橫向滑動時,會切換螢幕,當縱向滑動時,ListView會滾動。 效果圖如下: 程式碼如下: FlingGallery.

Android定義view-仿小米視訊載入動畫效果

*本篇文章已授權微信公眾號 guolin_blog (郭霖)獨家釋出 1、概述         前幾日出差,每晚回到酒店的時候,睡前打發時間就是拿起自己的小米手機擼劇,酒店的wifi網路實在太差,眼睜睜的看著小米視訊的載入動畫一直拼命的loading中,正好最近一直在看

Android 修改源碼定義SwipeRefreshLayout樣式——仿微信朋友圈下拉刷新

樣式 post and 微信 修改 size roi 自定義 details 修改源碼自定義SwipeRefreshLayout樣式——高仿微信朋友圈下拉刷新Android 修改源碼自定義SwipeRefreshLayout樣式——高仿微信朋友圈下拉

Android定義View的實現方法帶你一步步深入瞭解View(四)

不知不覺中,帶你一步步深入瞭解View系列的文章已經寫到第四篇了,回顧一下,我們一共學習了LayoutInflater的原理分析、檢視的繪製流程、檢視的狀態及重繪等知識,算是把View中很多重要的知識點都涉及到了。如果你還沒有看過我前面的幾篇文章,建議先去閱讀一下,多瞭解一些

Android定義View實戰】之定義評價打分控制元件RatingBar可以定義星星大小和間距

在Android開發中,我們經常會用到對商家或者商品的評價,運用星星進行打分。然而在Android系統中自帶的打分控制元件,RatingBar特別不好用,間距和大小無法改變。所以,我就自定義了一個特別好用的打分控制元件。在專案中可以直接使用,特別簡

Android定義view(一)打造絢麗的驗證碼

前言:我相信信念的力量,信念可以支撐起一個人,一個名族,一個國家。正如“人沒有夢想和鹹魚有什麼區別”一樣,我有信念,有理想,所以我正在努力向著夢想前進~。 自定義view,如果是我,我首先要看到自定義view的效果圖,然後再想想怎麼實現這種效果或功能,所以先貼

Android定義View的三種方式:繼承佈局繼承原生控制元件繼承View

 自定義View非常的常用,也是Android開發的一項基本技能,自定義View有三種方式:繼承佈局,繼承原生控制元件,繼承View。一、繼承佈局先看效果圖:程式碼實現:1.在layout資料夾中建立佈局title_view.xml,這一步根據自己需要寫,本例中的佈局如下:佈

Android定義View初探(二)——仿360垃圾清理

明天就是五一勞動節了,在這裡先祝各位程式猿勞動節快樂,別在加班了! 自從嘗試過寫自定義View(Android自定義View初探(一)——餅圖)之後,每當看到別人的應用時,總是在想別人的實現方式,或許,這就是程式猿的悲哀吧O(∩_∩)O~。 前兩天就想嘗試去

Android定義View-仿華為手機管家病毒查殺類似於雷達掃描動畫效果

最近在使用華為手機管家病毒查殺時有一個類似雷達掃描的動畫,發現該動畫旋轉軸未對準圓心,如下圖: 這樣不仔細看,看不出來,咱們放大看一下,放大後如下: 現在我們可以清楚看到這個問題,於是想自己實現一把,好了,為了便於理解,這裡就按照動畫所見內容依次展開來說。 先簡單的分析一

Android進階之定義View實戰(一)仿iOS UISwitch控制元件實現

一.引言 個人覺得,自定義View一直是Android開發最變換莫測、最難掌握、最具吸引力的地方。因為它涉及到的知識點比較多,想在實際應用中駕輕就熟,由淺入深,你需要掌握以下知識點: 1. View的繪製機制以及Canvas、Paint、Rect等的常用方