1. 程式人生 > >實現一個網易雲音樂的 BottomSheetDialog

實現一個網易雲音樂的 BottomSheetDialog

作者:林冠巨集 / 指尖下的幽靈

掘金:https://juejin.im/user/587f0dfe128fe100570ce2d8

部落格:http://www.cnblogs.com/linguanh/

GitHub : https://github.com/af913337456/

騰訊雲專欄: https://cloud.tencent.com/developer/user/1148436/activities

目錄

  • 前序
  • 直觀對比下 gif 效果
    • Android SDK 自帶的 BottomSheetDialog
    • 網易雲音樂 的 BottomSheetDialog
    • 我開源 的仿網易雲音樂 BottomSheetDialog
  • 核心程式碼簡述

前序:

因為APP 需要參照網易雲音樂的 BottomSheetDialog 的效果,找了一圈沒找到,所以動手寫了一個,涉及圈子裡經常露面的知識點有下面三點,也是個實戰應用

  • 事件分發系列的--衝突處理 & 分發順序
  • View 繪製流程的--Measure 模式
  • 相對螢幕取 View 的座標

先來直觀對比下 gif 效果

  • 首先是-- Android SDK 自帶的 BottomSheetDialog
  • 然後是--網易雲音樂 的 BottomSheetDialog
  • 最後是--我開源 的仿網易雲音樂 BottomSheetDialog

首先是-- Android SDK 自帶的 BottomSheetDialog

下面的 gif 圖是一個Android SDK 自帶的 BottomSheetDialog 內部加了 RecyclerView 列表控制元件的效果

可以看出:

  • 下滑動作會收起,隱藏掉 dialog
  • 上滑會完全展開
  • 展開後,才能滑動 RecyclerView 內部

其次

  • 如果你內部使用的是 ListView 列表控制元件,你會發現會有其他奇怪的情況。

然後是--網易雲音樂 的 BottomSheetDialog

下面的 gif 圖是一個Android 版 網易雲音樂BottomSheetDialog效果

可以看出:

  • 下滑動作會有範圍回彈,也就是下滑到一定距離才會收起,隱藏掉 dialog
  • 上滑不給展開
  • 能夠在半展開的情況下,內嵌滑動列表控制元件,例如 listView
  • 和列表控制元件滑動不衝突,在列表控制元件滑盡的時候,可以下滑隱藏dialog

最後是--我開源 的仿網易雲音樂 BottomSheetDialog

可以看出,效果和網易雲的一樣

核心程式碼簡述

SDK 的 BottomSheetDialog 內部佈局的結構如下:

--FrameLayout
--|--CoordinatorLayout
--|--|--FrameLayout
--|--|--|--Our ContentView // 最後是我們設定的 ContentView

CoordinatorLayout 在 Action_Move 事件時,必要的時候對其子 View 進行事件攔截,所以有第一個 gif 看到的效果,具體不詳說。

第一個步驟 --- 防止 CoordinatorLayoutOur ContentView 攔截事件

這裡使用 ListView 做例子,設定onTouch,在內部做適當時候的適當阻止CoordinatorLayout 攔截事件。

// ListView
setOnTouchListener(
    new OnTouchListener() {
        @SuppressLint("ClickableViewAccessibility")
        @Override
        public boolean onTouch(View v, MotionEvent event) {
            if (bottomCoordinator == null)
                return false;
            // 拿出當前列表第一個可見 item 的 pos
            int firstVisiblePos = getFirstVisiblePosition();
            switch (event.getAction()) {
                case MotionEvent.ACTION_DOWN:
                    downY = event.getRawY();
                    bottomCoordinator.requestDisallowInterceptTouchEvent(true);
                    break;
                case MotionEvent.ACTION_MOVE:
                    moveY = event.getRawY();
                    if ((moveY - downY) > 10) {
                        // 下滑情況
                        if (firstVisiblePos == 0 && isOverScroll) {
                            // 列表控制元件,例如 listView 已經滑到頭了,允許被攔截
                            bottomCoordinator.requestDisallowInterceptTouchEvent(false);
                            break;
                        }
                    }
                    // 上滑時,總是不允許被攔截,listView 消耗當前事件
                    bottomCoordinator.requestDisallowInterceptTouchEvent(true);
                    break;
                case MotionEvent.ACTION_UP:
                    break;
            }
            return false;
        }
    }
);

第二個步驟,讓 ListView 能在半展開的情況下,顯示完整的資料條數

重寫 onMeasure,使用自定義的測量模式。

// ListView
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
    if(bottomCoordinator == null){
        super.onMeasure(widthMeasureSpec, heightMeasureSpec);
        return;
    }
    // 以黃金分割的尺寸來顯示 listView 的高度
    int size = (int)((float)(getResources().getDisplayMetrics().heightPixels*0.618));
    int newHeightSpec = MeasureSpec.makeMeasureSpec(
            size,
            // mode,非法的情況,super 直接使用 size 做高,看原始碼後,你會發現也可以使用 exact 模式
            Integer.MIN_VALUE 
    );
    super.onMeasure(widthMeasureSpec, newHeightSpec);
}

第三個步驟,實現 BottomSheetDialog 範圍回彈

/**
 * 新增 top 距離頂部多少的時候觸發收縮效果
 * @param targetLimitH int 高度限制
 */
@SuppressWarnings("all")
public void addSpringBackDisLimit(final int targetLimitH){
    if(coordinator == null)
        return;
    // totalHeight 螢幕的總畫素高度
    final int totalHeight = getContext().getResources().getDisplayMetrics().heightPixels;
    // currentH 當前我們的 列表控制元件 展開的高度
    final int currentH = (int) ((float)totalHeight*0.618); // 0.618 是黃金分割點,隨便自定義,對應 contentView
    final int leftH    = totalHeight - currentH;
    coordinator.setOnTouchListener(
            new View.OnTouchListener() {
                @Override
                public boolean onTouch(View v, MotionEvent event) {
                    switch (event.getAction()){
                        case MotionEvent.ACTION_MOVE:
                            // 計算相對於螢幕的 座標
                            bottomSheet.getGlobalVisibleRect(r);
                            break;
                        case MotionEvent.ACTION_UP:
                            // 擡手的時候判斷
                            int limitH;
                            if(targetLimitH < 0)
                                limitH = (leftH + currentH/3);
                            else
                                limitH = targetLimitH;
                            if(r.top <= limitH)
                                if (mBehavior != null)
                                    // 範圍內,讓它繼續是 半展開的狀態
                                    mBehavior.setState(BottomSheetBehavior.STATE_COLLAPSED);
                            break;
                    }
                    return false;
                }
            }
    );
}

相關推薦

實現一個音樂BottomSheetDialog

作者:林冠巨集 / 指尖下的幽靈 掘金:https://juejin.im/user/587f0dfe128fe100570ce2d8 部落格:http://www.cnblogs.com/linguanh/ GitHub : https://github.com/af913337456/

利用Python網路爬蟲實現音樂歌詞爬取

今天小編給大家分享網易雲音樂歌詞爬取方法。 本文的總體思路如下: 找到正確的URL,獲取原始碼; 利用bs4解析原始碼,獲取歌曲名和歌曲ID; 呼叫網易雲歌曲API,獲取歌詞; 將歌詞寫入檔案,並存入本地。 本文的目的是獲取網易雲音樂的歌詞,並將歌詞存入到本地檔案。整

微信小程式 --- CSS實現仿音樂播放介面效果(黑膠唱片與唱針純CSS實現

下面程式碼的效果是網易雲音樂唱針和黑膠唱片的CSS效果實現方式,播放等並沒貼出來 實現效果的範圍 動態圖效果預覽: stylusW,panW是獲取系統寬度計算後的引數 w

Android ScrollView滾動實現大眾點評、音樂評論懸停效果

ins schema bar 音樂 layout mage for bin andro 今天聽著網易雲音樂,寫著代碼,真是爽翻了。 http://blog.csdn.net/linshijun33/article/details/47910833 網

用RotateDrawable實現音樂唱片機效果

image 不難 線程 們的 progress ogr icon 什麽 als 有一段時間沒有更新文章了,記得上一篇文章講的是《用ClipDrawable實現音頻錄制麥克風講話效果》,用戶反響也都還不錯,自己也是深受鼓勵。事實上從那之後就一直想寫一篇

零基礎實現音樂播放器

循環 case phone width shadow rec pda user res H5增加了很多的標簽,面試的時候,如果面試官問你H5都有哪些新標簽,你回答header、footer、nav。這麽回答幾乎是無效的,因為這些標簽在H5裏面的角色,相當於雞骨頭、魚刺、蘑菇

音樂數據交互—async&await實現版(完結篇)

mage mark 解決方案 必須 cat 留言 系列教程 自己 text 我們的網易雲音樂系列課,尾聲了,今天我們要將一個最重要的東西--關於ES7 async結合Fetch異步編程問題。 ES7 async/await被稱作異步編程的終極解決方案,我們先不管這個稱呼,咱

推薦一個高大上的音樂命令行播放工具:musicbox

setup.py 根據 load 開發 .py 排行 ogr class 圖片 網易雲音樂上有很多適合程序猿的歌單,但是今天文章介紹的不是這些適合程序員工作時聽的歌,而是一個用Python開發的開源播放器,專門適用於網易雲音樂的播放。這個播放器的名稱為MusicBox, 特

卡拉OK歌詞原理和實現高仿Android音樂

大家好,我們是愛學啊,繼上一篇講解了【LRC歌詞原理和實現高仿Android網易雲音樂】,今天給大家帶來一篇關於卡拉OK歌詞原理和在Android上如何實現歌詞逐字滾動的效果,本文來自【Android開發專案實戰我的雲音樂】課程。 效果圖 相信大家都懂一張圖勝過千言萬語。 效果和現在市面上大部分播放

推薦一個高大上的音樂命令列播放工具:musicbox

網易雲音樂上有很多適合程式猿的歌單,但是今天文章介紹的不是這些適合程式設計師工作時聽的歌,而是一個用Python開發的開源播放器,專門適用於網易雲音樂的播放。這個播放器的名稱為MusicBox, 特色是用命令列版本執行音樂的播放。 github地址: https://github.com/darkness

LRC歌詞原理和實現高仿Android音樂

大家好,我們是愛學啊,今天給大家帶來一篇關於LRC歌詞原理和在Android上如何實現歌詞逐行滾動的效果,本文來自【Android開發專案實戰我的雲音樂】課程;逐字滾動下一篇文章講解。 效果圖 相信大家都懂一張圖勝過千言萬語。 效果和現在市面上大部分播放器差不多,當然如果要運用到商業專案中,肯定還需

寫了一個模仿音樂APP輪播圖的小demo

效果圖: 放在了github上,裡面有比較詳細的註釋和思路的轉變 效果演示:效果演示 程式碼地址:l輪播圖程式碼地址 實現功能: 定時切換(3s) 滑鼠放上去停止切換 點選左右圖片進行圖片切換 滑鼠放上去顯示向左向右按鈕,滑鼠移下來再次隱藏 點

Python解密音樂.ncm檔案,將.ncm檔案轉換為.mp3檔案,實現隨處播放(另附C++已編譯轉換器)

網易雲音樂把.mp3音樂檔案加密為.ncm檔案,導致不能將下載好的音樂複製到其它裝置或使用非網易雲音樂播放器播放,該程式可將.ncm檔案逆向解密為.mp3檔案並保留最高音質。 另有C++已編譯.exe轉換器,將.ncm檔案拖到.exe上直接執行轉換,生成.mp3檔案在.ncm檔案相同路徑。點選下

音樂推薦系統簡單實現系列(1)

筆者最近面試到了網易新聞推薦部門,考了一點推薦系統的知識,算是被虐慘了。於是乎自己怒補了一些知識。記錄一點關於推薦系統的知識和實現。 音樂推薦系統,這裡的簡單指的是資料量級才2萬條,之後會詳細解釋。 1. 推薦系統工程師人才成長RoadMap

利用AudioContext來實現音樂的鯨魚音效

一直覺得網易雲音樂的使用者體驗是很不錯的,很早就注意到了裡面的鯨魚音效,如下圖,就是一個環形的跟著音樂節拍跳動的特效。 gif動圖可能效果不太理想,可以直接在手機上體驗 身為前端憑著本能的好奇心和探索心當然會研究一番,如何在頁面上實現該效果? 1.AudioCon

自定義外掛實現音樂首頁圖片輪播

編寫html介面 <!DOCTYPE html> <html> <head> <meta charset="utf-8" /> <title>網易雲音樂

案例:用vue開發音樂(已實現線上播放和下載)

效果如圖: 完整程式碼: <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content

Qt-音樂介面實現-7 訊息中心實現,主要是QListWidget 自定義Item 和QTabwidget使用

最近寫的有點煩躁, 感覺內容真的很多!很多!很多。目前真的想知道網易官方在出這款產品是,用了多少人和多長時間。今天寫的這個訊息中心,有點糙,只是原理實現了沒有完全複製過來,心裡有團火,不想寫了。看下效果吧其實這個訊息中心的內容到時很簡單,最底層一個Qtabwidgte,構成@

安卓 實現音樂底部播放欄效果之使用自定義BaseActivity實現

起因: 最近在寫一個音樂專案,發現網易雲音樂的底部播放欄看起來不錯,不同的頁面切換也能做到無縫連線,於是自己打算仿造一個。折磨: 1.一開始我看到知乎有大神說使用Activity+Fragment實現

用Java實現音樂爬蟲(非selenium)

主要內容: 使用httpclient(非模擬瀏覽器) 使用網易雲音樂api 採集:評論和使用者最近聽歌的統計 思路: 用一首歌的id作為入口,得到下面的所有評論 –> 取出