安卓音樂播放器歌詞滾動顯示

轉載請註明出處:http://blog.csdn.net/iwanghang/article/details/51386317

奇蹟在相信它的人眼裏纔是奇蹟

——— 歌德


本文系轉載,出處已經標明,以前寫播放器苦於音樂歌詞的顯示問題,當時解決的方法是去github找開源控件,無奈是別人的輪子,尺寸大小不對,只好湊活着用了,無聊逛了下csdn,發現有這篇文章,果斷收藏。以後歌詞顯示就直接自己造輪子用了~~~~~~~~~



實現功能:


歌詞顯示及滾動事件實現
ViewPager使用

後續將博文,將實現已下載音樂掃描功能和已存在歌曲歌詞下載。

因爲,沒有自己的服務器,所以網絡音樂所有相關功能(包含搜索音樂、下載音樂、下載歌詞)均無法保證時效性,建議,儘快下載和練習;如果你下載時候,已經因爲我採集的服務器更改規則,請給我留言,如果可以解決,我將在有空的時候獻上新的源碼。

截止到目前的源碼下載:
http://download.csdn.net/album/detail/3105
(最新的,請下載最後一個,本博文對應版本2.1;如果需要逐步實現的過程,請下載所有)

歡迎移動開發愛好者交流:我的微信是iwanghang

另外,我打算開始找工作,如果瀋陽或周邊城市公司有意,也請與我聯繫。

實現效果如圖:


實現代碼如下:

PlayActivity如下:


[java] view plain copy

  1. package com.iwanghang.drmplayer;  

  2.   

  3. import android.graphics.Bitmap;  

  4. import android.media.MediaPlayer;  

  5. import android.os.Bundle;  

  6. import android.os.Environment;  

  7. import android.os.Handler;  

  8. import android.os.Message;  

  9. import android.support.v4.view.ViewPager;  

  10. import android.support.v4.view.ViewPager.OnPageChangeListener;  

  11. import android.view.LayoutInflater;  

  12. import android.view.View;  

  13. import android.view.View.OnClickListener;  

  14. import android.widget.ImageView;  

  15. import android.widget.SeekBar;  

  16. import android.widget.SeekBar.OnSeekBarChangeListener;  

  17. import android.widget.TextView;  

  18. import android.widget.Toast;  

  19.   

  20. import com.douzi.android.view.DefaultLrcBuilder;  

  21. import com.douzi.android.view.ILrcBuilder;  

  22. import com.douzi.android.view.ILrcView;  

  23. import com.douzi.android.view.LrcRow;  

  24. import com.douzi.android.view.LrcView;  

  25. import com.iwanghang.drmplayer.adapter.ViewPagerAdapter;  

  26. import com.iwanghang.drmplayer.utils.Constant;  

  27. import com.iwanghang.drmplayer.utils.ImageUtils;  

  28. import com.iwanghang.drmplayer.utils.MediaUtils;  

  29. import com.iwanghang.drmplayer.vo.Mp3Info;  

  30. import com.lidroid.xutils.db.sqlite.Selector;  

  31. import com.lidroid.xutils.exception.DbException;  

  32.   

  33. import java.io.BufferedReader;  

  34. import java.io.File;  

  35. import java.io.FileInputStream;  

  36. import java.io.FileNotFoundException;  

  37. import java.io.IOException;  

  38. import java.io.InputStreamReader;  

  39. import java.lang.ref.WeakReference;  

  40. import java.util.ArrayList;  

  41. import java.util.List;  

  42.   

  43. import static com.iwanghang.drmplayer.PlayService.ORDER_PLAY;  

  44. import static com.iwanghang.drmplayer.PlayService.RANDOM_PLAY;  

  45. import static com.iwanghang.drmplayer.PlayService.SINGLE_PLAY;  

  46.   

  47.   

  48. /** 

  49.  * PlayActivity 點擊MyMusicListFragment(本地音樂)底部UI中的專輯封面圖片打開的Activity 

  50.  */  

  51. public class PlayActivity extends BaseActivity implements OnClickListener, OnSeekBarChangeListener ,OnPageChangeListener {  

  52.     private TextView textView2_title;//歌名  

  53.     private ImageView imageView1_ablum;//專輯封面圖片  

  54.     private SeekBar seekBar1;//進度條  

  55.     private TextView textView1_start_time, textView1_end_time;//開始時間,結束時間  

  56.     private ImageView imageView1_play_mode;//菜單  

  57.     private ImageView imageView3_previous, imageView2_play_pause, imageView1_next;//上一首,播放暫停,下一首  

  58.     private ImageView imageView1_ablum_reflection;//專輯封面圖片倒影  

  59.     private ImageView imageView1_favorite;//收藏按鈕  

  60.   

  61.     //private ArrayList<Mp3Info> mp3Infos;  

  62.     //private int position;//當前播放的位置  

  63.     private boolean isPause = false;//當前播放的是否爲暫停狀態  

  64.     private static final int UPDATE_TIME = 0x10;//更新播放事件的標記  

  65.   

  66.     private DRMPlayerApp app;//取出全局對象 方便調用  

  67.   

  68.     //歌詞  

  69.     private ViewPager viewPager;  

  70.     private LrcView lrcView;// 自定義歌詞視圖  

  71.     private ArrayList<View> views = new ArrayList<>();  

  72.     private static final int UPDATE_LRC = 0x20;//更新播放事件的標記  

  73.     ILrcView mLrcView;  

  74.     public final static String TAG = "PlayActivity";  

  75.     private MediaPlayer mPlayer;  

  76.     private ViewPagerAdapter adapter;  

  77.   

  78.     @Override  

  79.     protected void onCreate(Bundle savedInstanceState) {  

  80.         super.onCreate(savedInstanceState);  

  81.         setContentView(R.layout.activity_music_play);  

  82.         //取出全局對象 方便調用  

  83.         app = (DRMPlayerApp) getApplication();  

  84.         //初始化界面信息  

  85.        

  86.         seekBar1 = (SeekBar) findViewById(R.id.seekBar1);//進度條  

  87.         textView1_start_time = (TextView) findViewById(R.id.textView1_start_time);//開始時間  

  88.         textView1_end_time = (TextView) findViewById(R.id.textView1_end_time);//結束時間  

  89.         imageView1_play_mode = (ImageView) findViewById(R.id.imageView1_play_mode);//菜單  

  90.         imageView3_previous = (ImageView) findViewById(R.id.imageView3_previous);//上一首  

  91.         imageView2_play_pause = (ImageView) findViewById(R.id.imageView2_play_pause);//播放暫停  

  92.         imageView1_next = (ImageView) findViewById(R.id.imageView1_next);//下一首  

  93.         imageView1_favorite = (ImageView) findViewById(R.id.imageView1_favorite);//收藏按鈕  

  94.         lrcView = (LrcView) findViewById(R.id.lrcView);//自定義歌詞視圖  

  95.   

  96.         //註冊按鈕點擊監聽事件  

  97.         imageView1_play_mode.setOnClickListener(this);  

  98.         imageView2_play_pause.setOnClickListener(this);  

  99.         imageView3_previous.setOnClickListener(this);  

  100.         imageView1_next.setOnClickListener(this);  

  101.         seekBar1.setOnSeekBarChangeListener(this);  

  102.         imageView1_favorite.setOnClickListener(this);  

  103.   

  104.   

  105.         //mp3Infos = MediaUtils.getMp3Infos(this);  

  106.         myHandler = new MyHandler(this);  

  107.   

  108.         //獨立音樂播放界面 和 歌詞界面  

  109.         viewPager = (ViewPager) findViewById(R.id.viewpager);  

  110.         initViewPager();//初始化  

  111.           

  112.   

  113.         

  114.     

  115.    

  116.     }  

  117.   

  118.   

  119.     private void initViewPager() {//專輯封面圖片Pager與歌詞Pager  


  120.   

  121.         View album_image_layout = LayoutInflater.from(getApplicationContext()).inflate(R.layout.album_image_layout, null);  

  122.         System.out.println("PlayActivity.initViewPager.album_image_layout:" + album_image_layout);  

  123.   

  124.   

  125.         imageView1_ablum = (ImageView) album_image_layout.findViewById(R.id.imageView1_ablum);//專輯封面圖片  

  126.   

  127.         imageView1_ablum_reflection = (ImageView) album_image_layout.findViewById(R.id.imageView1_ablum_reflection);//專輯封面圖片倒影  

  128.   

  129.         views.add(album_image_layout);//添加專輯封面圖片Pager  

  130.   

  131.   

  132.   

  133.         //View lrc_layout = getLayoutInflater().inflate(R.layout.lrc_layout, null);  

  134.   

  135.   

  136.         View lrc_layout = LayoutInflater.from(getApplicationContext()).inflate(R.layout.lrc_layout, null);  

  137.         System.out.println("PlayActivity.initViewPager.lrc_layout:" + lrc_layout);  

  138.   

  139.   

  140.   

  141.         lrcView = (LrcView) lrc_layout.findViewById(R.id.lrcView);  

  142.         //設置滾動事件  

  143.         lrcView.setListener(new ILrcView.LrcViewListener() {  

  144.             @Override  

  145.             public void onLrcSeeked(int newPosition, LrcRow row) {  

  146.                 if (playService.isPlaying()) {  

  147.                     playService.seekTo((int) row.time);  

  148.                 }  

  149.             }  

  150.         });  

  151.         lrcView.setLoadingTipText("正在加載歌詞......");  

  152.         lrcView.setBackgroundResource(R.mipmap.app_splash_bg);  

  153.         lrcView.getBackground().setAlpha(150);//背景透明度0-255  

  154.         views.add(lrc_layout);  

  155.         System.out.println("PlayActivity.initViewPager.views:" + views);  

  156.   

  157.   

  158.   

  159.         //adapter = new ViewPagerAdapter(views);  

  160.         adapter = new ViewPagerAdapter(views);  

  161.         viewPager.setAdapter(adapter);  

  162.   

  163.   

  164.   

  165.   

  166.         //viewPager.setAdapter(new ViewPagerAdapter(views));  

  167.         System.out.println("PlayActivity.initViewPager.viewPager:" + viewPager);  

  168.         viewPager.addOnPageChangeListener(this);  

  169.         System.out.println("PlayActivity.initViewPager.viewPager:" + viewPager);  

  170.     }  

  171.   

  172.   

  173.   

  174.   

  175.   

  176.   

  177.     //把播放服務的綁定和解綁放在onResume,onPause裏,好處是,每次回到當前Activity就獲取一次播放狀態  

  178.     @Override  

  179.     protected void onResume() {  

  180.         super.onResume();  

  181.         bindPlayService();//綁定服務  

  182.     }  

  183.   

  184.     @Override  

  185.     protected void onPause() {  

  186.         super.onPause();  

  187.         unbindPlayService();//解綁服務  

  188.     }  

  189.   

  190.     @Override  

  191.     protected void onDestroy() {  

  192.         super.onDestroy();  

  193.         unbindPlayService();//解綁服務  

  194.     }  

  195.   

  196.     //Handler用於更新已經播放時間  

  197.     private static MyHandler myHandler;  

  198.   

  199.     //進度條改變 (fromUser 是否來自用戶的改變 , 而不是程序自身控制的改變)  

  200.     @Override  

  201.     public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) {  

  202.         if (fromUser) {  

  203.             //playService.pause();//暫停  

  204.             playService.seekTo(progress);//尋找指定的時間位置 (跳到某個時間點進行播放)  

  205.             //playService.start();//播放  

  206.         }  

  207.     }  

  208.   

  209.     //進度條開始觸摸  

  210.     @Override  

  211.     public void onStartTrackingTouch(SeekBar seekBar) {  

  212.   

  213.     }  

  214.   

  215.     //進度條停止觸摸  

  216.     @Override  

  217.     public void onStopTrackingTouch(SeekBar seekBar) {  

  218.   

  219.     }  

  220.   

  221.     //頁面滾動  

  222.     @Override  

  223.     public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {  

  224.   

  225.     }  

  226.   

  227.     //頁面選擇  

  228.     @Override  

  229.     public void onPageSelected(int position) {  

  230.   

  231.     }  

  232.   

  233.     //頁面滾動狀態改變  

  234.     @Override  

  235.     public void onPageScrollStateChanged(int state) {  

  236.   

  237.     }  

  238.   

  239.   

  240.     static class MyHandler extends Handler {  

  241.         private PlayActivity playActivity;  

  242.         private WeakReference<PlayActivity> weak;//弱引用  

  243.   

  244.         public MyHandler(PlayActivity playActivity) {  

  245.             //this.playActivity = playActivity;  

  246.             weak = new WeakReference<PlayActivity>(playActivity);  

  247.         }  

  248.   

  249.         @Override  

  250.         public void handleMessage(Message msg) {  

  251.             super.handleMessage(msg);  

  252.             //System.out.println("PlayActivity.MyHandler.weak = " + weak);  

  253.             playActivity = weak.get();  

  254.             //System.out.println("PlayActivity.MyHandler.playActivity = " + playActivity);  

  255.             if (playActivity != null) {  

  256.                 switch (msg.what) {  

  257.                     case UPDATE_TIME://更新時間(已經播放時間)  

  258.                         playActivity.textView1_start_time.setText(MediaUtils.formatTime((int) msg.obj));  

  259.                         break;  

  260.                     case UPDATE_LRC:  

  261.                         playActivity.lrcView.seekLrcToTime((int) msg.obj);  

  262.                         break;  

  263.                     default:  

  264.                         break;  

  265.                 }  

  266.             }  

  267.         }  

  268.     }  

  269.   

  270.   

  271.         

  272.         long id = getId(mp3Info);  

  273.   

  274.         //初始化收藏狀態  

  275.         try {  

  276.             Mp3Info loveMp3Info = app.dbUtils.findFirst(Selector.from(Mp3Info.class).where("mp3InfoId""=", mp3Info.getMp3InfoId()));//查出歌曲,SQL語句  

  277.             System.out.println("初始化收藏狀態" + loveMp3Info);  

  278. //            if (loveMp3Info != null) {  

  279. //                imageView1_favorite.setImageResource(R.mipmap.app_love_selected);  

  280. //            } else {  

  281. //                imageView1_favorite.setImageResource(R.mipmap.app_love_unselected);  

  282. //            }  

  283.          

  284.   

  285.         //歌詞  

  286.        

  287.     }  

  288.   

  289.                     playService.pause();  

  290.                 } else {  

  291.                     if (playService.isPause()) {  

  292.                         imageView2_play_pause.setImageResource(R.mipmap.app_music_pause);//設置暫停圖片  

  293.                         playService.start();//播放事件  

  294.                     } else {  

  295.                         //只有打開APP沒有點擊任何歌曲,同時,直接點擊暫停播放按鈕時.纔會調用  

  296.                         //playService.play(0);  

  297.   

  298.                         //只有打開APP沒有點擊任何歌曲,同時,直接點擊暫停播放按鈕時.纔會調用  

  299.                         //默認播放的是,在PlayService的onCreate中 恢復狀態值  

  300.                         playService.play(playService.getCurrentPosition());  

  301.                     }  

  302.                 }  

  303.                 break;  

  304.             }  

  305.             case R.id.imageView1_next: {//下一首按鈕  

  306.                 playService.next();//下一首  

  307.                 break;  

  308.             }  

  309.             case R.id.imageView3_previous: {//上一首按鈕  

  310.                 playService.prev();//上一首  

  311.                 break;  

  312.             }  

  313.             case R.id.imageView1_play_mode: {//循環模式按鈕  

  314.                 //int mode = (int) imageView1_play_mode.getTag();  

  315.                 /** 

  316.                  * 以下Tosat內容,在strings.xml裏,添加對應代碼 

  317.                  *<string name="order_play">順序播放</string> 

  318.                  *<string name="random_play">隨機播放</string> 

  319.                  *<string name="single_play">單曲循環</string> 

  320.                  */  

  321.                 switch (playService.getPlay_mode()) {  

  322.                     case ORDER_PLAY:  

  323.                         imageView1_play_mode.setImageResource(R.mipmap.app_mode_random);  

  324.                         //imageView1_play_mode.setTag(RANDOM_PLAY);  

  325.                         playService.setPlay_mode(RANDOM_PLAY);  

  326.                         //Toast.makeText(getApplicationContext(),"隨機播放",Toast.LENGTH_SHORT).show();//這句也可以  

  327.                         //Toast.makeText(PlayActivity.this, "隨機播放", Toast.LENGTH_SHORT).show();//這句也可以  

  328.                         Toast.makeText(PlayActivity.this, getString(R.string.random_play), Toast.LENGTH_SHORT).show();  

  329.                         break;  

  330.              

  331.                 break;  

  332.             }  

  333.             case R.id.imageView1_favorite: {//收藏按鈕  //在vo.Mp3Info裏  private long mp3InfoId;//在收藏音樂時用於保存原始ID  

  334.                 Mp3Info mp3Info = playService.mp3Infos.get(playService.getCurrentPosition());//查出歌曲  

  335.   

  336.     }  

  337.   

  338.   

  339.     //加載歌詞  

  340.     private void loadLRC(File lrcFile){  

  341.         StringBuffer buf = new StringBuffer(1024 * 10);  

  342.         char[] chars = new char[1024];  

  343.         try {  

  344.             BufferedReader in = new BufferedReader(new InputStreamReader(new FileInputStream(lrcFile)));  

  345.             int len = -1;  

  346.             while ((len = in.read(chars)) != -1){  

  347.                 buf.append(chars,0,len);  

  348.             }  

  349.             in.close();  

  350.         } catch (FileNotFoundException e) {  

  351.             e.printStackTrace();  

  352.         }catch (IOException e) {  

  353.             e.printStackTrace();  

  354.         }  

  355.         ILrcBuilder builder = new DefaultLrcBuilder();  

  356.         List<LrcRow> rows = builder.getLrcRows(buf.toString());  

  357.         lrcView.setLrc(rows);  

  358.         //加載專輯封面圖片爲背景的方法(實際使用,發現效果不理想)  

  359.         //long id = mp3Info.getMp3InfoId()==0?mp3Info.getId:mp3Info.getMp3InfoId();  

  360.         //Bitmap bg = MediaUtils.getArtwork(this, id ,mp3Info.getAlbumId(),false,false);  

  361.         //if(bg != null){  

  362.         //    lrcView.getBackground(new BitmapDrawable(getResources(),bg));  

  363.         //   lrcView.getBackground().setAlpha(120);  

  364.         //}  

  365.  

ViewPagerAdapter如下:


[java] view plain copy

  1. package com.iwanghang.drmplayer.adapter;  

  2.   

  3. import android.content.Context;  

  4. import android.os.Parcelable;  

  5. import android.support.v4.view.PagerAdapter;  

  6. import android.support.v4.view.ViewPager;  

  7. import android.view.View;  

  8. import android.view.ViewGroup;  

  9. import android.widget.ImageView;  

  10. import android.widget.TextView;  

  11.   

  12. import java.util.List;  

  13.   

  14. /** 

  15.  * Created by iwanghang on 16/5/10. 

  16.  * ViewPagerAdapter 

  17.  */  

  18. public class ViewPagerAdapter extends PagerAdapter {  

  19.     private List<View> list;  

  20.     private Context context;  

  21.   

  22.     public ViewPagerAdapter(List<View> list) {  

  23.         this.list = list;  

  24.     }  

  25.   

  26.     public ViewPagerAdapter(List<View> list,Context context) {  

  27.         this.list = list;  

  28.         this.context = context;  

  29.     }  

  30.   

  31.     @Override  

  32.     public int getCount() {  

  33.         if (list != null && list.size() > 0) {  

  34.             return list.size();  

  35.         } else {  

  36.             return 0;  

  37.         }  

  38.     }  

  39.   

  40.     @Override  

  41.     public boolean isViewFromObject(View arg0, Object arg1) {  

  42.         return arg0 == arg1;  

  43.     }  

  44.   

  45.     @Override  

  46.     public void destroyItem(ViewGroup container, int position, Object object) {  

  47.         container.removeView((View) object);  

  48.     }  

  49.   

  50.     @Override  

  51.     public Object instantiateItem(ViewGroup container, int position) {  

  52.         container.addView(list.get(position));  

  53.         return list.get(position);  

  54.     }  

  55.   

  56.     @Override  

  57.     public int getItemPosition(Object object) {  

  58.         return POSITION_NONE;  

  59.     }  

  60.   

  61.   

  62.   

  63.   

  64.   

  65.   

  66.   

  67. }  



發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章