1. 程式人生 > >【android】音樂播放器之UI設計的點點滴滴

【android】音樂播放器之UI設計的點點滴滴

       學習Android有一個多月,看完了《第一行程式碼》以及mars老師的第一期視訊通過音樂播放器小專案加深對知識點的理解。從本文開始,將詳細的介紹簡單仿多米音樂播放器的實現,以及網路解析資料獲取百度音樂最新排行音樂以及下載功能。

        功能介紹如下:    

        1、獲取本地歌曲列表,實現歌曲播放功能。 
        2、利用jsoup解析網頁資料,從網路獲取歌曲列表,同時實現歌曲和歌詞下載到手機本地的功能。 
        3、通知欄提醒,實現仿QQ音樂播放器的通知欄功能. 

      涉及的技術有: 
       1、jsoup解析網路網頁,從而獲取需要的資料 
       2、android中訪問網路,獲取檔案到本地的網路請求技術,以及下載檔案到本地實現斷點下載 
       3、執行緒池 
       4、圖片快取 
       5、service一直在後臺執行 
       6、Activity與Fragment間的切換以及通訊 
       7、notification通知欄設計 
       8、自定義廣播 
       9、android系統檔案管

 Ui介面的最終顯示效果如下:



 馬上來看看UI介面是如何實現的,不過先得做些準備工作~~啟動介面的設計。細心的朋友肯定注意到目前一些主流app登陸時候都有封面展示的效果,啟動介面的製作就是為了實現這個效果:載入一個佈局全屏展示一張封面,並2s跳轉到主佈局MainActivity.

public class SplashActivity extends Activity{
	@Override
	protected void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		// no title
		requestWindowFeature(Window.FEATURE_NO_TITLE);
		// 全屏
		getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN,
				WindowManager.LayoutParams.FLAG_FULLSCREEN);
		setContentView(R.layout.splash_layout);
		
		// 2s跳轉到主介面
		new Handler().postDelayed(new Runnable() {
			@Override
			public void run() {
				startActivity(new Intent(SplashActivity.this, MainActivity.class));
				finish();
			}
		}, 2000);
	}
}

有了上面的準備工作,可以設計主介面以及主介面中的5個Fragment(不是4個嘛!!!!~!~我這邊直接將本地音樂列表這個Fragment直接放到MainActivity中)。目前,主流的app主介面實現由四種方式:

 (1)ViewPager實現

        (2)Fragment實現

        (3)FragmentPagerAdapter+ViewPager實現

        (4)ViewPagerIndicator+ViewPager實現

      就挑個最熟練的實現方式:Fragment實現。(哈哈,目前水平比較低。。。ViewPager後文有使用分析,其餘還是想每一種都有機會去嘗試用到程式碼中去。) 小編這邊的都是使用動態Fragment

  1. <LinearLayoutxmlns:android="http://schemas.android.com/apk/res/android"
  2.     xmlns:tools="http://schemas.android.com/tools"
  3.     android:layout_width="match_parent"
  4.     android:layout_height="match_parent"
  5.     android:orientation="vertical">
  6.     <includelayout="@layout/top"/>
  7.     <FrameLayout
  8.         android:id="@+id/id_content"
  9.         android:layout_width="fill_parent"
  10.         android:layout_height="0dp"
  11.         android:layout_weight="1">
  12.     </FrameLayout>
  13.     <includelayout="@layout/bottom"/>
  14. </LinearLayout>
頂部和底部的佈局就補貼出來了,到時直接看原始碼就明白了。在MainActivity中通過監聽底部的按鈕獲取FragmentManager方式開啟一個事務新增一個Fragment或者去隱藏一個Fragment。當然這邊也可以直接呼叫事務的raplace方法替代原佈局中的Fragment(~·~後文將介紹相關的Api以及總結Fragment和Activity的通訊),主要程式碼段如下:
  1. public void setSelect(int i)  
  2.     {  
  3.         FragmentManager fm = getSupportFragmentManager();  
  4.         FragmentTransaction transaction = fm.beginTransaction();  
  5.         hideFragment(transaction);  
  6.         // 把圖片設定為亮的  
  7.         // 設定內容區域  
  8.         switch (i)  
  9.         {  
  10.         case TAB_USER:  
  11.             if (mTab01 == null)  
  12.             {  
  13.                 mTab01 = new UserFragment();  
  14.                 transaction.add(R.id.id_content, mTab01);  
  15.             } else  
  16.             {  
  17.                 transaction.show(mTab01);  
  18.             }  
  19.             mImguser.setImageResource(R.drawable.icon_user_selected);  
  20.             mTitle.setText("我的音樂");  
  21.             break;  
  22.         case TAB_CD:  
  23.             if (mTab02 == null)  
  24.             {  
  25.                 mTab02 = new CdFragment();  
  26.                 transaction.add(R.id.id_content, mTab02);  
  27.             } else  
  28.             {  
  29.                 transaction.show(mTab02);  
  30.             }  
  31.             mImgcd.setImageResource(R.drawable.icon_cd_selected);  
  32.             mTitle.setText("音樂架");  
  33.             break;  
  34.         case TAB_SEARCH:  
  35.             if (mTab03 == null)  
  36.             {  
  37.                 mTab03 = new SearchFragment();  
  38.                 transaction.add(R.id.id_content, mTab03);  
  39.             } else  
  40.             {  
  41.                 transaction.show(mTab03);  
  42.             }  
  43.             mImgsearch.setImageResource(R.drawable.icon_search_selected);  
  44.             mTitle.setText("搜尋");  
  45.             break;  
  46.         case TAB_COMPASS:  
  47.             if (mTab04 == null)  
  48.             {  
  49.                 mTab04 = new CompassFragment();  
  50.                 transaction.add(R.id.id_content, mTab04);  
  51.             } else  
  52.             {  
  53.                 transaction.show(mTab04);  
  54.             }  
  55.             mImgcompass.setImageResource(R.drawable.icon_compass_selected);  
  56.             mTitle.setText("發現");  
  57.             break;  
  58.         case TAB_SONGLIST:  
  59.             if (mTab05 == null)  
  60.             {  
  61.                 mTab05 = new LocalFragment();  
  62.                 transaction.add(R.id.id_content, mTab05);  
  63.             } else  
  64.             {  
  65.                 transaction.show(mTab05);  
  66.             }  
  67.             resetImgs();  
  68.             setVisibility(TOP_MENU);  
  69.             mTitle.setText("本地音樂");  
  70.             break;  
  71.         default:  
  72.             break;  
  73.         }  
  74.         transaction.commit();  
  75.     }  
  1. private void hideFragment(FragmentTransaction transaction)  
  2.     {  
  3.         setVisibility(TOP_JUMP);  
  4.         if (mTab01 != null)  
  5.         {  
  6.             transaction.hide(mTab01);  
  7.         }  
  8.         if (mTab02 != null)  
  9.         {  
  10.             transaction.hide(mTab02);  
  11.         }  
  12.         if (mTab03 != null)  
  13.         {  
  14.             transaction.hide(mTab03);  
  15.         }  
  16.         if (mTab04 != null)  
  17.         {  
  18.             transaction.hide(mTab04);  
  19.         }  
  20.         if (mTab05 != null)  
  21.         {  
  22.             transaction.hide(mTab05);  
  23.         }  
  24.     }  

 每個Fragment中的控制元件也都是最最常用的控制元件,這邊就不一一介紹。。。其餘除Ui之外更詳細的分析可以看看小編其他相關的部落格。其中,應該注意的是:在本地音樂這個Fragment中通過短點選ListView歌曲Items跳轉啟動PlayAcyivity載入播放介面。也終於到了講ViewPager這塊了!!!~!~
       ViewPager新增一個VIew或者刪除一個View是通過我們自定義的PagerAdapter控制的,於是我們可以在View中維繫一個ArrayList<view>。然後滑動的時候通過get(position)取出對應的view:

       ViewPager新增一個VIew或者刪除一個View是通過我們自定義的PagerAdapter控制的,於是我們可以在View中維繫一個ArrayList<view>。然後滑動的時候通過get(position)取出對應的view:
  1. /**  
  2.      * 初始化viewpager的內容  
  3.      */  
  4.     private void initViewPagerContent() {  
  5.         View cd = View.inflate(this, R.layout.play_pager_item_1, null);  
  6.         mCdView = (CDView) cd.findViewById(R.id.play_cdview);  
  7.         mTextArtistTitle = (TextView) cd.findViewById(R.id.play_singer);  
  8.         mLrcViewOnFirstPage = (LrcView) cd.findViewById(R.id.play_first_lrc);  
  9.         View lrcView = View.inflate(this, R.layout.play_pager_item_2, null);  
  10.         mLrcViewOnSecondPage = (LrcView) lrcView.findViewById(R.id.play_first_lrc_2);  
  11.         mViewPagerContent.add(cd);  
  12.         mViewPagerContent.add(lrcView);  
  13.     }  
  1. private PagerAdapter mPagerAdapter = new PagerAdapter() {  
  2.         @Override  
  3.         public int getCount() {  
  4.             return mViewPagerContent.size();  
  5.         }  
  6.         @Override  
  7.         public boolean isViewFromObject(View view, Object obj) {  
  8.             return view == obj;  
  9.         }  
  10.         @Override  
  11.         public Object instantiateItem(ViewGroup container, int position) {  
  12.             container.addView(mViewPagerContent.get(position));  
  13.             return mViewPagerContent.get(position);  
  14.         }  
  15.         @Override  
  16.         public void destroyItem(ViewGroup container, int position, Object object) {  
  17.             ((ViewPager) container).removeView((View) object);  
  18.         }  
  19.     };  
         內容太多了,只能講主要的Ui佈局實現。其他細節可以參考我其他博文或者原始碼。

下面我想共享下下面的一些關於Fragment的小總結!

        Fragment家族常用的API

 Fragment常用的三個類:(1)android.app.Fragment 主要用於定義Fragment;(2)android.app.FragmentManager 主要用於在Activity中操作Fragment;(3)android.app.FragmentTransaction 保證一些列Fragment操作的原子性,熟悉事務這個詞,一定能明白~

a、獲取FragmentManage的方式:getFragmentManager() // v4中,getSupportFragmentManager

b、主要的操作都是FragmentTransaction的方法:1)FragmentTransaction transaction = fm.benginTransatcion();//開啟一個事務;2)transaction.add() 往Activity中新增一個Fragment;3)transaction.remove()從Activity中移除一個Fragment,如果被移除的Fragment沒有新增到回退棧(回退棧後面會詳細說),這個Fragment例項將會被銷燬;4)transaction.replace():使用另一個Fragment替換當前的,實際上就是remove()然後add()的合體~;5)transaction.hide():隱藏當前的Fragment,僅僅是設為不可見,並不會銷燬;6)transaction.show():顯示之前隱藏的Fragment

7)detach()會將view從UI中移除,和remove()不同,此時fragment的狀態依然由FragmentManager維護;8)attach()重建view檢視,附加到UI上並顯示。

transatcion.commit()//提交一個事務

        注意:常用Fragment的哥們,可能會經常遇到這樣Activity狀態不一致:State loss這樣的錯誤。主要是因為:commit方法一定要在Activity.onSaveInstance()之前呼叫。

         上述,基本是操作Fragment的所有的方式了,在一個事務開啟到提交可以進行多個的新增、移除、替換等操作。值得注意的是:如果你喜歡使用Fragment,一定要清楚這些方法,哪個會銷燬檢視,哪個會銷燬例項,