Honeycombチュートリアル その5

HoneycomicGallery タイトル一覧用のFragmentを作成する

Title一覧を表示するFragmentを作成する。選択したタイトルと画像の連携はまだ行わない

手順

====================

  1. レイアウトファイルの作成
    1. title_list_item.xml
  2. Title一覧を表示するフラグメントを作成する
    1. TitlesFragment.java
  3. サイズリソースの作成
    1. dimens.xml
  4. main.xmlの修正
    1. TitlesFragmentを追加する
  5. MainActivityの修正
    1. TitlesFragmentと連携する

Title一覧を表示するFragmentの作成

===================================

ListFragmentを継承したTitleFragmentを作成する。
ListFragmentは内部に既にListViewを持ったレイアウトを設定されているので、専用のレイアウトファイルを必要としない。

レアウトを作成する
                                      • -

ListFragmentはレイアウトxmlを必要としなkが、行のレイアウトは必要になる

title_list_row.xml
                                    • -
    <?xml version="1.0" encoding="utf-8"?>
    <TextView
        xmlns:android="http://schemas.android.com/apk/res/android"
        android:padding="10dp"
        android:gravity="bottom"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:textAppearance="?android:attr/textAppearanceMedium"
        android:background="?android:attr/activatedBackgroundIndicator">
    </TextView>
Fragmentの作成
                                          • -

Title一覧用のFragmentを作成する

  1. フィールドの追加
    1. private int category
    2. private int curPosition
  2. メソッドのオーバライド
    1. onActivityCreated
  3. メソッドの追加
    1. populateTitles
    2. selectPosition
    3. onListItemClick
    4. updateImage
フィールドの追加

選択中のカテゴリとアイテムをフィールドで管理

   private int category = 0;
   private int curPosition = 0;
onActvityCreated
  • Fragmentの初期化を行うためonActvityCreatedをオーバライドする。
  • populateTitlesメソッドを呼び出しAdapterを設定する

ListFragmentが持っているListViewはListFragment#getListViewで取得できる。
ListView#setChoiceModeでListView.CHOICE_MODE_SINGLEを指定し、1つだけ選択できるようにする。

onListItemClick

onListItemClickメソッドをオーバライドし、タイトルを選択した時に画像の更新処理を追加する。

updateImage

画像の更新処理を行うが、現段階ではContentFragmentの連携はできないのでログを出力する

TitlesFragment.java
	package com.hidecheck.honeycomic;
	
	import android.app.ListFragment;
	import android.os.Bundle;
	import android.util.Log;
	import android.view.View;
	import android.widget.ArrayAdapter;
	import android.widget.ListView;
	
	public class TitlesFragment extends ListFragment {
	    private int category = 0;
	    private int curPosition = 0;
		
	    @Override
		public void onActivityCreated(Bundle savedInstanceState) {
			super.onActivityCreated(savedInstanceState);
			
			populateTitles(category);
			ListView lv = getListView();
			lv.setChoiceMode(ListView.CHOICE_MODE_SINGLE);
			// TODO OnLongItemClickListner 
			
	        selectPosition(curPosition);
	
		}
	    
	    public void populateTitles(int category) {
	    	
	    	DirectoryCategory cat = Directory.getCategory(category);
	    	String[] items = new String[cat.getEntryCount()];
	    	for(int i = 0; i < cat.getEntryCount(); i++){
	    		items[i] = cat.getEntry(i).getName();
	    	}
	    	setListAdapter(new ArrayAdapter<String>(getActivity(), R.layout.title_list_item, items));
	    	this.category = category;
	        Log.v("TitlesFragment", "category:" +cat.getName() + " " + this.category);
	    }
	
	    public void selectPosition(int position) {
	        ListView lv = getListView();
	        lv.setItemChecked(position, true);
	        
	        //TODO updateImage
	
	    }
	
		@Override
		public void onListItemClick(ListView l, View v, int position, long id) {
			updateImage(position);
		}
		
	    private void updateImage(int position) {
	    	// TODO change image
	    	
	        curPosition = position;
	        Log.v("TitlesFragment", "current position:" + curPosition);
	    }
	}
create dimens.xml
                                  • -

Title幅を定義

dimens.xml
    <?xml version="1.0" encoding="utf-8"?>
    <resources>
        <dimen name="titles_size">300dp</dimen>
    </resources>
change main.xml
                                  • -

TitlesFragmentを追加する。layout_widthに@dimen/titles_sizeを指定する

main.xml
    <?xml version="1.0" encoding="utf-8"?>
    <LinearLayout
        xmlns:android="http://schemas.android.com/apk/res/android"
        android:orientation="horizontal"
        android:id="@+id/flags"
        android:layout_width="fill_parent"
        android:layout_height="fill_parent">
    
        <fragment class="com.example.android.hcgallery.TitlesFragment"
                android:id="@+id/frag_title"
                android:visibility="gone"
                android:layout_marginTop="?android:attr/actionBarSize"
                android:layout_width="@dimen/titles_size"
                android:layout_height="match_parent" />
    
    
        <fragment
            class="com.hidecheck.honeycomic.ContentFragment"
            android:id="@+id/frag_content"
            android:layout_width="match_parent"
            android:layout_height="match_parent" />
    </LinearLayout>
MainActivityの修正
                                        • -

onTabSelectedメソッドを修正する。
Activity#getFragmentManagerメソッドを使ってTitleFragmentを取得する

		TitlesFragment titleFrag = (TitlesFragment) getFragmentManager().findFragmentById(R.id.frag_title);
public FragmentManager getFragmentManager ()

FragmentManagerを取得する

  • public abstract Fragment findFragmentById (int id)
    • ResourceIDを指定してFragmentを取得する
引数 意味
int id リソースID
MainActivity.java
                                          • -
	package com.hidecheck.honeycomic;
	
	import android.app.ActionBar;
	import android.app.ActionBar.Tab;
	import android.app.Activity;
	import android.app.FragmentTransaction;
	import android.os.Bundle;
	import android.view.Menu;
	import android.view.MenuInflater;
	import android.view.MenuItem;
	import android.view.View;
	
	public class MainActivity extends Activity implements ActionBar.TabListener {
	
		private View actionvBarView;
	
		/** Called when the activity is first created. */
		@Override
		public void onCreate(Bundle savedInstanceState) {
			super.onCreate(savedInstanceState);
			setContentView(R.layout.main);
	
			Directory.initializeDirectory();
	
			// Create ActionBar
			ActionBar bar = getActionBar();
	
			for (int i = 0; i < Directory.getmCategoryCount(); i++) {
				bar.addTab(bar.newTab().setText(Directory.getCategory(i).getName())
						.setTabListener(this));
			}
	
			// bar customizition.
			actionvBarView = getLayoutInflater().inflate(R.layout.action_bar_custom, null);
			bar.setCustomView(actionvBarView);
			bar.setDisplayOptions(ActionBar.DISPLAY_SHOW_CUSTOM | ActionBar.DISPLAY_USE_LOGO);
			bar.setNavigationMode(ActionBar.NAVIGATION_MODE_TABS);
			bar.setDisplayShowHomeEnabled(true);
			
		}
	
		@Override
		public void onTabReselected(Tab tab, FragmentTransaction ft) {
	
		}
	
		@Override
		public void onTabSelected(Tab tab, FragmentTransaction ft) {
	
			TitlesFragment titleFrag = (TitlesFragment) getFragmentManager().findFragmentById(R.id.frag_title);
			titleFrag.populateTitles(tab.getPosition());
			titleFrag.selectPosition(0);
		}
	
		@Override
		public void onTabUnselected(Tab tab, FragmentTransaction ft) {
	
		}
	
		@Override
		public boolean onCreateOptionsMenu(Menu menu) {
			MenuInflater inflater = getMenuInflater();
			inflater.inflate(R.menu.main_menu, menu);
			return true;
		}
	
		@Override
		public boolean onOptionsItemSelected(MenuItem item) {
			return super.onOptionsItemSelected(item);
		}
	}
実行結果
                              • -

default

selected title

logcat

selected tab

logcat


端末向き変更対応

=======================================
端末の向きを変えるとデフォルトのアイテムに戻ってしまうので、画面向き対応の処理を追加する。

Fragment#onSaveInstanceStateで現在設定を保存し、Fragment#onActivityCreatedとActivity#onSaveInstanceStateで設定を取得しているところに注意

  1. TitlesFragmentの変更
    1. onActivityCreatedを修正する
    2. onSaveInstanceStateメソッドのオーバライド
  2. MainActivityを修正する
    1. onCreateメソッドの修正
    2. onSaveInstanceStateの修正
TitlesFragmentの変更
                                                  • -

onSaveInstanceStateで設定を保存し、onActivityCreatedで設定を取り出す

onActivityCreated

引数savedInstanceStateから直前のcategoryとlistPositionを取得する

	        //Current position should survive screen rotations.
			if(savedInstanceState != null){
				category = savedInstanceState.getInt("category");
				curPosition = savedInstanceState.getInt("listPosition");
			}
onSaveInstanceState

現在のcategoryとlistPositionを保存する

		@Override
		public void onSaveInstanceState(Bundle outState) {
			super.onSaveInstanceState(outState);
	        outState.putInt("listPosition", curPosition);
	        outState.putInt("category", category);
		}
TitleFragment.java
	package com.hidecheck.honeycomic;
	
	import android.app.ListFragment;
	import android.os.Bundle;
	import android.util.Log;
	import android.view.View;
	import android.widget.ArrayAdapter;
	import android.widget.ListView;
	
	public class TitlesFragment extends ListFragment {
	    private int category = 0;
	    private int curPosition = 0;
		
	    @Override
		public void onActivityCreated(Bundle savedInstanceState) {
			super.onActivityCreated(savedInstanceState);
			
	        //Current position should survive screen rotations.
			if(savedInstanceState != null){
				category = savedInstanceState.getInt("category");
				curPosition = savedInstanceState.getInt("listPosition");
			}
			
			populateTitles(category);
			ListView lv = getListView();
			lv.setChoiceMode(ListView.CHOICE_MODE_SINGLE);
			// TODO OnLongItemClickListner 
			
	        selectPosition(curPosition);
	
		}
	    
	    public void populateTitles(int category) {
	    	
	    	DirectoryCategory cat = Directory.getCategory(category);
	    	String[] items = new String[cat.getEntryCount()];
	    	for(int i = 0; i < cat.getEntryCount(); i++){
	    		items[i] = cat.getEntry(i).getName();
	    	}
	    	setListAdapter(new ArrayAdapter<String>(getActivity(), R.layout.title_list_item, items));
	    	this.category = category;
	        Log.v("TitlesFragment", "category:" +cat.getName() + " " + this.category);
	    }
	
		@Override
		public void onSaveInstanceState(Bundle outState) {
			super.onSaveInstanceState(outState);
	        outState.putInt("listPosition", curPosition);
	        outState.putInt("category", category);
		}
		
	    public void selectPosition(int position) {
	        ListView lv = getListView();
	        lv.setItemChecked(position, true);
            updateImage(position);
	    }
	    
		@Override
		public void onListItemClick(ListView l, View v, int position, long id) {
			updateImage(position);
		}
		
	    private void updateImage(int position) {
	    	// TODO change image
	    	
	        curPosition = position;
	        Log.v("TitlesFragment", "current position:" + curPosition);
	    }
	
	}
MainActivityの修正
                                            • -

onSaveInstanceStateで直前の設定を取り出す

onSaveInstanceState

		@Override
		protected void onSaveInstanceState(Bundle outState) {
			super.onSaveInstanceState(outState);
	        ActionBar bar = getActionBar();
	        int category = bar.getSelectedTab().getPosition();
	        outState.putInt("category", category);
	        
	        // TODO save Theme id
	        
		}
MainActivity.java
                                      • -
	package com.hidecheck.honeycomic;
	
	import android.app.ActionBar;
	import android.app.ActionBar.Tab;
	import android.app.Activity;
	import android.app.FragmentTransaction;
	import android.os.Bundle;
	import android.view.Menu;
	import android.view.MenuInflater;
	import android.view.MenuItem;
	import android.view.View;
	
	public class MainActivity extends Activity implements ActionBar.TabListener {
	
		private View actionvBarView;
	
		/** Called when the activity is first created. */
		@Override
		public void onCreate(Bundle savedInstanceState) {
			super.onCreate(savedInstanceState);
			setContentView(R.layout.main);
	
			Directory.initializeDirectory();
	
			// Create ActionBar
			ActionBar bar = getActionBar();
	
			for (int i = 0; i < Directory.getmCategoryCount(); i++) {
				bar.addTab(bar.newTab().setText(Directory.getCategory(i).getName())
						.setTabListener(this));
			}
	
			// bar customizition.
			actionvBarView = getLayoutInflater().inflate(R.layout.action_bar_custom, null);
			bar.setCustomView(actionvBarView);
			bar.setDisplayOptions(ActionBar.DISPLAY_SHOW_CUSTOM | ActionBar.DISPLAY_USE_LOGO);
			bar.setNavigationMode(ActionBar.NAVIGATION_MODE_TABS);
			bar.setDisplayShowHomeEnabled(true);
			
	        // If category is not saved to the savedInstanceState,
	        // 0 is returned by default.
	        if(savedInstanceState != null) {
	            int category = savedInstanceState.getInt("category");
	            bar.selectTab(bar.getTabAt(category));
	        }
	
		}
	
		@Override
		public void onTabReselected(Tab tab, FragmentTransaction ft) {
	
		}
	
		@Override
		public void onTabSelected(Tab tab, FragmentTransaction ft) {
	
			TitlesFragment titleFrag = (TitlesFragment) getFragmentManager().findFragmentById(R.id.frag_title);
			titleFrag.populateTitles(tab.getPosition());
			titleFrag.selectPosition(0);
		}
	
		@Override
		public void onTabUnselected(Tab tab, FragmentTransaction ft) {
	
		}
	
		@Override
		public boolean onCreateOptionsMenu(Menu menu) {
			MenuInflater inflater = getMenuInflater();
			inflater.inflate(R.menu.main_menu, menu);
			return true;
		}
	
		@Override
		public boolean onOptionsItemSelected(MenuItem item) {
			return super.onOptionsItemSelected(item);
		}
	
		@Override
		protected void onSaveInstanceState(Bundle outState) {
			super.onSaveInstanceState(outState);
	        ActionBar bar = getActionBar();
	        int category = bar.getSelectedTab().getPosition();
	        outState.putInt("category", category);
	        
	        // TODO save Theme id
	        
		}
	
	}
実行結果
                              • -

向き変更

.. image:: images/04_create_fragment02_2.png