Android用(ちょっと)本格的なミュージックプレーヤの開発 part3

一週あいてしまいましたが Android用ミュージックプレーヤの開発
3回目です。 今回は一気にライブラリ画面がそれっぽくなります。

今回は先日まで作った
TrackとAlbumの一覧メニューに加えてArtistの一覧を作り、
最後に1つの画面で切り替えて使えるようにホームを整えます。

Artist管理クラス

これはTrackのコードをほぼ流用してしまってOKです。

public class Artist {

        public long                     id;
        public String           artist;
        public String           artistKey;
        public int                      albums;
        public int                      tracks;

        public static final String[] FILLED_PROJECTION = {
                MediaStore.Audio.Artists._ID,
                MediaStore.Audio.Artists.ARTIST,
                MediaStore.Audio.Artists.ARTIST_KEY,
                MediaStore.Audio.Artists.NUMBER_OF_ALBUMS,
                MediaStore.Audio.Artists.NUMBER_OF_TRACKS,
        };

        public Artist(Cursor cursor){
                id                      =cursor.getLong(  cursor.getColumnIndex( MediaStore.Audio.Artists._ID              ));
                artist          =cursor.getString(cursor.getColumnIndex( MediaStore.Audio.Artists.ARTIST           ));
                artistKey       =cursor.getString(cursor.getColumnIndex( MediaStore.Audio.Artists.ARTIST_KEY       ));
                albums          =cursor.getInt(   cursor.getColumnIndex( MediaStore.Audio.Artists.NUMBER_OF_ALBUMS ));
                tracks          =cursor.getInt(   cursor.getColumnIndex( MediaStore.Audio.Artists.NUMBER_OF_TRACKS ));
        }

        public static List getItems(Context activity) {

                List artists = new ArrayList();

                ContentResolver resolver = activity.getContentResolver();
                Cursor cursor = resolver.query(
                                MediaStore.Audio.Artists.EXTERNAL_CONTENT_URI, 
                                Artist.FILLED_PROJECTION, 
                                null,
                                null,
                                "ARTIST  ASC"
                                );

                while( cursor.moveToNext() ){
                artists.add(new Artist(cursor));
        }

        cursor.close();
                return artists;
        }

}

Googleで使用可能なカラムを調べつつさらっと書いていきます。
この後いつもと同様に XMLでデザインを上げて

さらに ListArtistAdapter を実装しますが、これはもはやTrackのコピーに
過ぎないので割愛します。

上記画像の info 2つにはそれぞれ 保持アルバム数とトラック数を表示
します。

holder.albumsTextView.setText(String.format("%d Albums", item.albums));
holder.tracksTextView.setText(String.format("%d tracks", item.tracks));

こんなかんじでOKです。

複数画面の表示に対応

ここまでで Track Album Artist の一覧が表示できるようになりましたが、
先日のサンプルまでは画面が1つしか表示できないので、
Trackの表示を一旦削除してAlbumを表示させたりしていました。
今回は、これらの画面をスワイプで切り替えながら表示できるように
していきます。

これは Pagerを用いることで実現可能です。

まずはXMLにてデザインを組み立てます。

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:orientation="vertical"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:gravity="center_horizontal"
    >
<android.support.v4.view.ViewPager
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:id="@+id/pager"
    android:layout_width="match_parent"
    android:layout_height="0px"
    android:layout_weight="1"
    tools:context=".Main" >
    <android.support.v4.view.PagerTabStrip
                android:id="@+id/pager_title_strip"
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:layout_gravity="bottom"
                android:background="#111111"
                android:paddingBottom="4dp"
                android:paddingTop="4dp"
                android:textColor="#fff" />
</android.support.v4.view.ViewPager>
</LinearLayout>

画面いっぱいにPagerと下部に現在のPageを表示するPagerTabStripを配置しました。
ちなみに今回は移植性を高めるために一応 supportライブラリのPagerを使いました。

続いて実際にページを切り替える処理を書いていきます。

まずは、RootMenu という名前の Fragment (android.support.v4.app.Fragment;)
を継承したクラスを作成します。通常のFragmentをインポートした場合一部名前が
変わったりするので注意してください。

public class RootMenu extends Fragment {

                SectionsPagerAdapter mSectionsPagerAdapter;
                ViewPager mViewPager;

         @Override
         public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
                View rootView = inflater.inflate(R.layout.menu, container, false);

                mSectionsPagerAdapter = new SectionsPagerAdapter(getChildFragmentManager());
                        mViewPager = (ViewPager) rootView.findViewById(R.id.pager);
                        mViewPager.setAdapter(mSectionsPagerAdapter);

                        /*PagetTabカスタム*/
                        PagerTabStrip strip = (PagerTabStrip) rootView.findViewById(R.id.pager_title_strip);
                        strip.setTextSize(TypedValue.COMPLEX_UNIT_SP, 14);
                        strip.setTextSpacing(50);
                strip.setNonPrimaryAlpha(0.3f);

                return rootView;
            }

         public class SectionsPagerAdapter extends FragmentPagerAdapter {

                        public SectionsPagerAdapter(FragmentManager fm) {super(fm);}

                        @Override
                        public Fragment getItem(int position) {
                                Fragment fragment = null;
                                switch(position){
                                case 0: fragment = new HomeSectionFragment();   break;
                                case 1: fragment = new TrackSectionFragment();  break;
                                case 2: fragment = new AlbumSectionFragment();  break;
                                case 3: fragment = new ArtistSectionFragment(); break;
                                }
                                return fragment;
                        }

                        @Override
                        public int getCount() { return 4; }

                        @Override
                        public CharSequence getPageTitle(int position) {
                                switch (position) {
                                        case 0: return getString(R.string.title_section1);
                                        case 1: return getString(R.string.title_section2);
                                        case 2: return getString(R.string.title_section3);
                                        case 3: return getString(R.string.title_section4);
                                }
                                return null;
                        }

                }

      ~以下略~

まずは上の用に実装します。
onCreateViewでは、先ほど作成したXMLデザインを読み込んで rootView を作成します。
あとでこのrootView さんをMainActivityから呼び出すことでメニューが表示されます。

mSectionsPagerAdapter = new SectionsPagerAdapter(getChildFragmentManager());
mViewPager = (ViewPager) rootView.findViewById(R.id.pager);
mViewPager.setAdapter(mSectionsPagerAdapter);

この3行でPagerの設定を行なっています。
やっていることは ListViewの時と変わりません。
SectionPagerAdapter を作って setAdapter で rootView上のPagerViewに登録
する流れです。

そしてこのSectionPagerAdapter Classですが、直後に実装しています。
本当は別ファイルに分割してもいいのですが、他に使いまわしづらいので
RootMenu 内で実装します。

処理内容は実は

新しいAndroidプロジェクトを作成した時に表示されるこれを大体コピーして参考にすれば
OKです。やっていることはやはり ListViewのアダプターづくりと大差ありません。

getItem にてそれぞれのFragmentを出力するので、指定されたページごとに
出力すべきFragmentを作成して返しているだけです。
このクラスにはその他に、 全部で何ページ登録されているか返答する
getCount や現在開いているページのタイトルを返す getPageTitle() などが
必要なのでそれぞれ作成します。

onCreateViewに目を戻して、
/PagetTabカスタム/
というコメントのあとにある数行では、画面下部にて現在表示中のページを
表示してくれる PagerTabの動作設定を行なっています。
テキストサイズや、それぞれのタイトルの距離、非表示の画面タイトルの
半透明度などです。

Pager と PagetTab の設定が終わったら rootViewを 返して終了です。

ここまで作成できたら画面切り替えの準備は終わっています。
最後に、それぞれのページに出力するFragmentを作成すればOKです。
これもおそらく再利用しづらいのでRootMenuの中に作成します。

public static class HomeSectionFragment extends Fragment {

        @Override
        public View onCreateView(LayoutInflater inflater, ViewGroup container,
                Bundle savedInstanceState) {
                        View v = inflater.inflate(R.layout.menu_home, container, false);
                        return v;
                        }
        }

これがシンプルなFragment表示用のクラスです。

inflaterで layout.menu_home

を読み込んで作成した View を返すだけです。
このViewがSectionsPagerAdapterのgetItem 内で呼び出されてそれぞれの
ページとして表示されるようになります。
同様にページを作成していきます。

public static class TrackSectionFragment extends Fragment {
        @Override
        public View onCreateView(LayoutInflater inflater, ViewGroup container,
                Bundle savedInstanceState){
                    super.onCreate(savedInstanceState);

                    Main activity = (Main)getActivity();
                    List tracks = Track.getItems(activity);

                    View v = inflater.inflate(R.layout.menu_tracks,container,false);
                    ListView trackList = (ListView) v.findViewById(R.id.list);
                    ListTrackAdapter adapter = new ListTrackAdapter(activity, tracks);
                    trackList.setAdapter(adapter);

                  return v;

              }

}

これはTrackの一覧を表示する例です。
getActivityでMainのコンテキストを取得してこれをつかって Track.getItem を動かします。
前回の例では呼び出してるのがアクティビティ自信だったのでTrack.getItems(this)でしたが
今回は Track.getItems(activity) になっています。
その後はこれまでとほぼ同じです。

inflaterでレイアウトを読み込みアダプターを登録するいつもの流れです。

Album , Artist 用の画面も同様に処理します。

これでページ切り替えの準備も完了しました。

最後にMainActivityを改造すればおしまいです。

まずはデザインを組みます。画面の白い部分に先ほど作成したPagerを
載せます。 ついでに下部にテスト用のボタンを配置しました。
まだボタンを押した時の処理はできていませんが一応。。。
(音がなるようになったらちゃんと絵素材を用意して差し替えましょう)

デザインができたらソースの方も更新します。

public class Main extends FragmentActivity{

        @Override
        protected void onCreate(Bundle savedInstanceState) {
                super.onCreate(savedInstanceState);

                FragmentManager fm = getSupportFragmentManager();
                FragmentTransaction ft = fm.beginTransaction();
                ft.replace(R.id.root, new RootMenu(),"Root");
                ft.commit();

                setContentView(R.layout.activity_main);
        }

        @Override
        public boolean onCreateOptionsMenu(Menu menu) {

                getMenuInflater().inflate(R.menu.main, menu);

                return true;
        }

}

今までリストビューを表示していた代わりに最初のフラグメントを積み立てる処理を
書いています。フラグメントマネージャに先ほど作成した
RootMenu() を登録します。

ちなみに今回は supportライブラリからFragment系のインポートを行なっているので
Mainクラスは Activity ではなく FramgnetActivity を継承するように変更します。

これで今回の全ての追加が完了しました。仮想環境でテストしてみましょう。

こんなかんじです。

起動直後は HOME screen が表示されており
右にスワイプしていくと トラック アルバム アーティスト
などの表示が切り替わっていきます。

画面下部の操作パネルもちゃんと表示されていますね。

お疲れ様です。
次回は、このアルバム一覧から、アルバムを指定すると、
個別メニューが表示されるようにします


コメントを追加する