欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

Android 基于RecyclerView實現(xiàn)的歌詞滾動自定義控件

 更新時間:2018年03月22日 09:23:04   作者:恒夕  
這篇文章主要介紹了Android 基于RecyclerView實現(xiàn)的歌詞滾動自定義控件,小編覺得挺不錯的,現(xiàn)在分享給大家,也給大家做個參考。一起跟隨小編過來看看吧

本文介紹了Android 基于RecyclerView實現(xiàn)的歌詞滾動自定義控件,分享給大家,具體如下:

先來幾張效果圖:

這幾天打算做一個控件,來讓自己復習一下自定義 view 的知識以及事件分發(fā)機制的原理與應用。對于這個控件,我已經(jīng)封裝好了,只要調用就可以了。

本來是想放上 gitHub 和 添加依賴的。但是提交 github 出了問題一直不會弄,所以就只能先等等了。((;′⌒`))

接下來說一下實現(xiàn)原理:

該控件分為以下幾個部分:

  1. 歌詞自動滾動
  2. 歌詞顏色字體變化
  3. 觸碰屏幕歌詞不滾動,高亮顯示,離開時自動移動到當前歌詞位置
  4. 觸碰屏幕中間線條出現(xiàn)以及顯示該歌詞的時間
  5. 點擊歌詞跳轉到當前位置并輸出當時時間
  6. 可設置跳轉時間跳到相應歌詞位置

接下來我一個一個大概講述一下思路。

1.對于滾動,我們可以調用 RecyclerView.smoothScrollBy() 方法,

相對于 ScrollBy() 方法,該方法能夠實現(xiàn)平滑滑動。

我設置了總共顯示九句歌詞。而且因為我想在歌詞前面和后面留一些空白,這些看起來會好看些。所以,在歌詞列表里面我加多了一些空白。

List<String> wordList = new ArrayList<>();
    wordList.add("");
    wordList.add("");
    wordList.add("");
    wordList.add("");
    wordList.addAll(mWordList);
    wordList.add("");
    wordList.add("");
    wordList.add("");
    wordList.add("");

由于歌詞的滾自動滾動是根據(jù)歌詞時間來進行移動的。所以我們需要需要使用 Runable 來執(zhí)行滾動操作。而且為了避免內存泄漏。將 Runable 實現(xiàn)類修飾為 static 。所以歌詞列表索引位置有所變化。

private static class AutoPullWork implements Runnable {
    public AutoPullWork(AutoPullRecyclerView autoPullRecyclerView) {
      weakReference = new WeakReference<AutoPullRecyclerView>(autoPullRecyclerView);
    }
    @Override
    public void run() {
    autoPullRecyclerView.smoothScrollBy(0, autoPullRecyclerView.getMeasuredHeight() / 9);
    autoPullRecyclerView.postDelayed(autoPullRecyclerView.autoPullWork, autoPullRecyclerView.timeList.get(autoPullRecyclerView.currentWord - 4) - autoPullRecyclerView.timeList.get(autoPullRecyclerView.currentWord - 5));
    ......

2.對于歌詞的高亮顯示,我們可以調用 notifyItemChange(int position) 方法,這個方法調用會重新去繪制特定 position 上的 viewHolder 。hightLightItem() 在這個方法中設置我們想要改變 viewHolder 的位置,并調用 notifyItemChange(int position) 。然后在 onBindViewHolder() 中的設置可以判斷當前是否需要高亮顯示。

public void hightLightItem(int position){
     mHighLightPosition = position;
     notifyItemChanged(position-1);
     notifyItemChanged(position);
  }
private boolean isHighLight(int position){
    return mHighLightPosition == position;
  }
@Override
  public void onBindViewHolder(ViewHolder holder, int position) {
    String word = mWordList.get(position);
    holder.textView.setText(word);

    try {
      if (!isHighLight(position)) {
        holder.textView.setTextSize(mOrdinarySize);
        holder.textView.setTextColor(Color.parseColor(mOrdinaryColor));

      } else if (isHighLight(position)) {
        holder.textView.setTextSize(mHighLightSize);
        holder.textView.setTextColor(Color.parseColor(mHighLightColor));
      }
    }catch ( Exception e){
      e.printStackTrace();
    }
  }

3.對于歌詞自動移動到當前語句:

本身我的想法就是多設置一個變量還是在這個 Runable() 里面進行操作。但是一個很嚴重的問題,導致我連續(xù)幾天一直想不到對策方法。由于手指離開屏幕的時候我使用 postDelayed() 方法有可能跟里面 Runable 里面使用的 postDelayed() 時間上可能會相互沖突,事件的執(zhí)行情況就很有可能變得跟你想不一樣。所以我們應該重新寫一個 Runable() 來控制它的自動移動到當前位置。這樣子的話各做各的事情,在寫邏輯的時候會比較容易理順。(當時沒想好害我調了好久,一直都不對,哈哈).

/**
   * 歌詞自動滑動到特定位置任務
   */
  private static class AutoBackWork implements Runnable{

    @Override
    public void run() {
    } 
  }

對于點擊屏幕時就重寫 onTouchEvent() 方法,

在 down 事件中 ,設置變量讓 Runable () 事件中不滾動。

而對于歌詞在離開屏幕后的一段時間后自動回到該位置。同樣的,還是需要使用 smoothScrollBy() 方法移動。而移動多少呢?這是個問題。這個要分為四種情況:

第一種:

當前歌詞在屏幕之外:由于我是打算將歌詞移動到屏幕中的第四個位置。

那么我就需要找到屏幕中的第一個位置,還有當前顯示的是哪一句歌詞。

由于我是想要讓他顯示在屏幕的第四行,所以是相差 currentWord + 5 - firstPosition 個位置 。

第二種:

當歌詞在第四行之前但是在第一行之后。

第三種:

當歌詞在第四行之后但是在最后一行之前。

第四種:

當歌詞在最后一行之后。

其實我們就根據(jù)自己想要在顯示在第幾行來判斷需要移動多少個位置。

我就不詳說啦,具體看代碼:

AutoPullRecyclerView autoPullRecyclerView = weakReference.get();
      LinearLayoutManager linearLayoutManager = (LinearLayoutManager) autoPullRecyclerView.getLayoutManager();
      int firtPosition = linearLayoutManager.findFirstVisibleItemPosition();
      int lastPosition = linearLayoutManager.findLastVisibleItemPosition();

      if (firtPosition>autoPullRecyclerView.currentWord){ // 第一種
        autoPullRecyclerView.smoothScrollBy(0, -(firtPosition - autoPullRecyclerView.currentWord + 5) * height);
      }else if(firtPosition+9>autoPullRecyclerView.currentWord){ 
        if (firtPosition+3>autoPullRecyclerView.currentWord){ // 第二種
          int top = autoPullRecyclerView.getChildAt(autoPullRecyclerView.currentWord-firtPosition).getTop();
          autoPullRecyclerView.smoothScrollBy(0, -(4*height-top)); //-- 
        }else{  // 第三種
          int top = autoPullRecyclerView.getChildAt(autoPullRecyclerView.currentWord-firtPosition).getTop();
          autoPullRecyclerView.smoothScrollBy(0,top-(4*height)); //++
        }
      }else { // 第四種
        autoPullRecyclerView.smoothScrollBy(0, (autoPullRecyclerView.currentWord - lastPosition + 5) * height);
      }
     }
 }

4.顯示中間線條以及顯示該歌詞時間

中間的 view 不可能鑲嵌在 RecyclerView 中。所以我們要自定義一個布局來放自定義 RecyclerView 和中間的 view。

這個是整個的 xml 文件。

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout
  xmlns:android="http://schemas.android.com/apk/res/android"
  android:clickable="true"
  android:layout_width="match_parent"
  android:layout_height="match_parent">
  <com.example.administrator.animationview.AutoPullRecyclerView
    android:id="@+id/auto_word"
    android:layout_width="match_parent"
    android:layout_height="match_parent"/>
  <RelativeLayout
    android:layout_centerVertical="true"
    android:id="@+id/divide_line"
    android:layout_width="match_parent"
    android:layout_height="wrap_content">
  <ImageView
    android:id="@+id/item_play_here"
    android:layout_marginStart="8dp"
    android:layout_centerVertical="true"
    android:src="@drawable/play"
    android:layout_width="20dp"
    android:layout_height="20dp" />
  <View
    android:id="@+id/divide_line1"
    android:layout_marginEnd="48dp"
    android:layout_marginStart="4dp"
    android:layout_toEndOf="@+id/item_play_here"
    android:layout_centerVertical="true"
    android:background="#E6E6FA"
    android:layout_width="match_parent"
    android:layout_height="1px"/>
  <TextView
    android:id="@+id/time1"
    android:layout_marginEnd="4dp"
    android:layout_alignParentEnd="true"
    android:layout_centerVertical="true"
    android:textSize="12sp"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content" />
  </RelativeLayout>

</RelativeLayout>

中間線的邏輯是當點擊屏幕的時候顯示出中間的線,離開屏幕的時候過一小段時間消失。也就是需要處理 down 事件和 up 事件 。但是我們在 RecyclerView 中是處理了點擊事件的,而且本身 RecyclerView 就已經(jīng)重寫了攔截了該事件的。而且一般是父 View 是不攔截事件的。那我們要怎么在里面設置 down 時間和 up 事件呢?我們怎么能讓父 View 接收到事件處理了一下同時最后又是子 view 處理事件呢?

在此,我推薦一篇博客,里面很詳細地介紹了事件分發(fā)處理機制的流程。

http://www.dbjr.com.cn/article/103134.htm
http://www.dbjr.com.cn/article/103141.htm

我先說一下結論吧。就是重寫 dispatchTouchEvent() 。因為假如我們重寫 onTouchEvent 的話,由于 RecyclerView 處理了事件。是不會處理這個方法的。

而對于 dispatchTouchEvent() 方法 ,如果你是在子 view 中處理事件。那么每次事件都會從 dispatchTouchEvent() 往下傳遞。具體原理可以看一下源碼。

@Override
  public boolean dispatchTouchEvent(MotionEvent ev) {
    switch (ev.getAction()){
      case MotionEvent.ACTION_DOWN:
        performClick();
        view.setVisibility(VISIBLE);
        show = true;
        view.setOnClickListener(new OnClickListener() {
          @Override
          public void onClick(View view) {
            autoPullRecyclerView.setComeToPlay();
            onClickListener.onClickListener(mCurrentTime);
          }
        });
        break;
      case MotionEvent.ACTION_UP:
        view.removeCallbacks(runnable);
        view.postDelayed(runnable,4000);
        break;
      default:
        break;
    }
    return super.dispatchTouchEvent(ev);
  }

對于顯示歌詞的時間,由于線條是在最中間的部分,我想要的是中間的線在哪一個 item 里面顯示該 item 對應時間。對于最原先的做法,我是通過 firstPosition 第一個看到的 item 變化時便變化時間。但是如果只是靠第一個可視化位置的話,由于中間線的位置,這樣會導致恰好在中間的位置往上移動一點和往下移動一點是兩個不同的時間變化。但是此時都是在同一 item 中 。所以我做的是去第二個可視化位置,判斷該位置離 top 與 item/2 的距離的比較。從而解決問題。

最開始只是根據(jù)第一個可視化位置而顯示的時間,但是顯示時間變化的位置不對。

改了思路根據(jù)第二個可視化位置之后根據(jù)位移來判斷。

private void showTime(){
    int height = autoPullRecyclerView.getMeasuredHeight() / 9;
    int top = autoPullRecyclerView.getChildAt(1).getTop();
    int currentPosition = linearLayoutManager.findFirstVisibleItemPosition();
    int position;
    if (top > height / 2) {
      position = currentPosition;
    } else {
      position = currentPosition + 1;
    }

點擊歌詞跳轉并且返回時間

點擊歌詞的時候改變高亮的位置和恢復原先的高亮的位置,并且通過回調返回時間。

case MotionEvent.ACTION_DOWN:
        performClick();
        view.setVisibility(VISIBLE);
        show = true;
        view.setOnClickListener(new OnClickListener() {
          @Override
          public void onClick(View view) {
            autoPullRecyclerView.setComeToPlay();
            onClickListener.onClickListener(mCurrentTime);
          }
        });
        break;
/**
   * 點擊歌詞滑動
   */
  public void setComeToPlay(){
    type =3;
    comeToPlay = true;
    lastWord = currentWord-1;
    removeCallbacks(autoPullWork);
    post(autoPullWork);
  }

5.點擊進度條跳轉到相應位置

先調用 seekBar 的 onSeekBarChangeListener() 中監(jiān)聽方法,獲取當前時間,根據(jù)時間獲得當前應該所處的索引。然后調用自動移動滾動方法和高亮方法。

seekBar.setOnSeekBarChangeListener(new SeekBar.OnSeekBarChangeListener() {
      @Override
      public void onProgressChanged(SeekBar seekBar, int i, boolean b) {

      }

      @Override
      public void onStartTrackingTouch(SeekBar seekBar) {

      }

      @Override
      public void onStopTrackingTouch(SeekBar seekBar) {
        int progress = seekBar.getProgress();    // 獲取當前進度
        worldRelativeLayout.setChangeTime(progress);
      }
    });

這次做一個自定義 View 控件,讓我有好幾點感觸,我記錄一下,一方面是希望告誡自己,一方面也算是分享給他人吧。

當你要做某個控件或項目的時候,不要著急著動筆。要先想好整個流程和框架。這方面先考慮清楚在動筆寫。你的邏輯一定要現(xiàn)在白紙上實現(xiàn)一遍后才開始敲代碼。就像我之前做的項目還有這次這個控件,我都比較著急寫。等到開始運行的時候,出現(xiàn)了跟我想的不太一樣。那我又根據(jù)結果去改代碼,但是這可能只是代表著某一個方面而已,下次有可能其他方面出問題了。這樣你就會被問題牽著走,而不能從整體上去看問題。

事情總是一點一點一點地解決。在寫代碼的過程中,總有我們當時不知道的,不會的,不知道怎么做的。但是也正是因為這些東西我們才會擴展了更多,豐富了許多,從另一個方面講,這也是在跳出舒適區(qū)吧,所以不要慌張,作為工程師,或者說作為生活的人,我們都需要有耐心和熱情。

以上就是本文的全部內容,希望對大家的學習有所幫助,也希望大家多多支持腳本之家。

相關文章

  • 詳解Android Studio 3.0的新特性與適配

    詳解Android Studio 3.0的新特性與適配

    這篇文章主要介紹了詳解Android Studio 3.0的新特性與適配,小編覺得挺不錯的,現(xiàn)在分享給大家,也給大家做個參考。一起跟隨小編過來看看吧
    2017-11-11
  • Android組件之DrawerLayout實現(xiàn)抽屜菜單

    Android組件之DrawerLayout實現(xiàn)抽屜菜單

    DrawerLayout組件同樣是V4包中的組件,也是直接繼承于ViewGroup類,所以這個類也是一個容器類。接下來通過本文給大家介紹Android組件之DrawerLayout實現(xiàn)抽屜菜單,感興趣的朋友一起學習吧
    2016-02-02
  • Android中的HOOK技術是什么

    Android中的HOOK技術是什么

    最近一段時間在研究Android加殼和脫殼技術,其中涉及到了一些hook技術,于是將自己學習的一些hook技術進行了一下梳理,以便后面回顧和大家學習
    2023-02-02
  • Android編程實現(xiàn)啟動另外的APP及傳遞參數(shù)的方法

    Android編程實現(xiàn)啟動另外的APP及傳遞參數(shù)的方法

    這篇文章主要介紹了Android編程實現(xiàn)啟動另外的APP及傳遞參數(shù)的方法,涉及Activity啟動及Intent設置相關操作技巧,需要的朋友可以參考下
    2017-05-05
  • Android中post請求傳遞json數(shù)據(jù)給服務端的實例

    Android中post請求傳遞json數(shù)據(jù)給服務端的實例

    下面小編就為大家分享一篇Android中post請求傳遞json數(shù)據(jù)給服務端的實例,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧
    2018-01-01
  • Flutter隨機迷宮生成和解迷宮小游戲功能的源碼

    Flutter隨機迷宮生成和解迷宮小游戲功能的源碼

    這篇文章主要介紹了Flutter隨機迷宮生成和解迷宮小游戲,本文通過實例代碼給大家介紹的非常詳細,對大家的學習或工作具有一定的參考借鑒價值,需要的朋友可以參考下
    2020-04-04
  • Android7.0以上Uri轉路徑的方法實現(xiàn)(已驗證)

    Android7.0以上Uri轉路徑的方法實現(xiàn)(已驗證)

    這篇文章主要介紹了Android7.0以上Uri轉路徑的方法實現(xiàn),文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧
    2020-03-03
  • Android自定義view之3D正方體效果實例

    Android自定義view之3D正方體效果實例

    這篇文章主要給大家介紹了關于Android自定義view之3D正方體效果的相關資料,實現(xiàn)的效果非常不錯,文中通過示例代碼介紹的非常詳細,需要的朋友可以參考下
    2021-08-08
  • android圖像繪制(二)畫布上放大縮小問題

    android圖像繪制(二)畫布上放大縮小問題

    android中圖像在畫布上放大縮小時,圖像的邊框大小沒有改變,很是疑惑,應該怎樣解決呢?接下來為您詳細介紹,感興趣的的朋友可以了解下
    2013-01-01
  • Android自定義View實現(xiàn)圓環(huán)交替效果

    Android自定義View實現(xiàn)圓環(huán)交替效果

    這篇文章給大家介紹如何基于Android自定義View實現(xiàn)圓環(huán)交替的效果,實現(xiàn)后效果很贊,有需要的小伙伴們可以參考借鑒。
    2016-08-08

最新評論