2013年12月31日火曜日

ListFragmentを使ってみる(setListShown)

ListFragmentの事を調べていたらsetListShownというメソッドをハヶ━m9( ゚д゚)っ━ン!!

setListShownを使うと、ListFragmentの表示領域にプログレスを表示することができるそうです。
これを利用してListFragmentの初期化や更新中に、表示させる事で多少見た目は良くなるかも?

■AndroidManifest.xml
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.example.listfragment4"
    android:versionCode="1"
    android:versionName="1.0" >

    <uses-sdk
        android:minSdkVersion="8"
        android:targetSdkVersion="17" />

    <application
        android:allowBackup="true"
        android:icon="@drawable/ic_launcher"
        android:label="@string/app_name"
        android:theme="@style/AppTheme" >
        <activity
            android:name="com.example.listfragment4.MainActivity"
            android:label="@string/app_name" >
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />

                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>
    </application>

</manifest>
■activity_main.xml

ListFragmentと同階層に、ボタンを2つ設置してあります。
この2つのボタンを操作する事で、setListShownのON/OFFが切り替わるようにしてあります。
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical" >

    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:orientation="horizontal" >

        <Button
            android:id="@+id/show"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:layout_weight="1"
            android:onClick="buttonclick"
            android:text="表示" />

        <Button
            android:id="@+id/hide"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:layout_weight="1"
            android:onClick="buttonclick"
            android:text="非表示" />
    </LinearLayout>

    <LinearLayout
        android:id="@+id/list"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:gravity="center_vertical"
        android:orientation="vertical" >
    </LinearLayout>

</LinearLayout>
■MyListFragment.java
package com.example.listfragment4;

import java.util.ArrayList;

import android.os.Bundle;
import android.support.v4.app.FragmentActivity;
import android.support.v4.app.ListFragment;
import android.util.Log;
import android.view.Gravity;
import android.view.View;
import android.view.ViewGroup;
import android.view.ViewGroup.LayoutParams;
import android.widget.AdapterView;
import android.widget.AdapterView.OnItemLongClickListener;
import android.widget.ArrayAdapter;
import android.widget.LinearLayout;
import android.widget.ListView;
import android.widget.TextView;

public class MyListFragment extends ListFragment {

 private static final String TAG = "MyListFragment";
 //
 private ListView mListView = null;
 //
 private ArrayList<String> mList = new ArrayList<String>();
 private ArrayAdapter<String> mAdapter = null;

 /*
  * 親となるActivityの「onCreate」の終了
  * 
  * @see android.support.v4.app.Fragment#onActivityCreated(android.os.Bundle)
  */
 @Override
 public void onActivityCreated(Bundle savedInstanceState) {
  super.onActivityCreated(savedInstanceState);

  Log.d(TAG, "onActivityCreated");

  // アダプター生成
  mAdapter = new ArrayAdapter<String>(getActivity(),
    android.R.layout.simple_list_item_1, mList);

  FragmentActivity activity = getActivity();

  // ListViewを取得する
  mListView = getListView();

  /*
   * ヘッダーの作成
   * 
   * 大枠のビューに対してsetLayoutParamsを利用すると、
   * Caused by: java.lang.ClassCastException: android.widget.LinearLayout$LayoutParams
   * というエラーが発生してしまう・・・orz
   */
  LinearLayout header = new LinearLayout(activity);
  // 縦に並べる
  header.setOrientation(LinearLayout.VERTICAL);

  // TextViewを生成する
  TextView textView = new TextView(activity);
  // 幅、高さの設定
  LinearLayout.LayoutParams layoutTextView = new LinearLayout.LayoutParams(
    LinearLayout.LayoutParams.MATCH_PARENT,
    LinearLayout.LayoutParams.WRAP_CONTENT);
  textView.setLayoutParams(layoutTextView);
  // 文字の位置の設定
  textView.setGravity(Gravity.CENTER);
  // 文字を設定
  textView.setText("HEADER");
  // フォントサイズ変更
  textView.setTextSize(14.0f);

  // ヘッダーにTextViewを追加する
  header.addView(textView);

  /*
   * フッターの作成
   */
  LinearLayout footer = new LinearLayout(activity);
  // 縦に並べる
  footer.setOrientation(LinearLayout.VERTICAL);

  // TextViewを生成する
  textView = new TextView(activity);
  textView.setLayoutParams(layoutTextView);
  // 文字の位置の設定
  textView.setGravity(Gravity.CENTER);
  // 文字を設定
  textView.setText("FOOTER");
  // フォントサイズ変更
  textView.setTextSize(14.0f);

  // ヘッダーにTextViewを追加する
  footer.addView(textView);

  // setListAdapterの前に設定する
  mListView.addHeaderView(header);
  mListView.addFooterView(footer);

  // アダプターの設定
  setListAdapter(mAdapter);

  //
  mListView.setOnItemLongClickListener(new OnItemLongClickListener() {

   /*
    * アイテムの長押し
    * 
    * @see
    * android.widget.AdapterView.OnItemLongClickListener#onItemLongClick
    * (android.widget.AdapterView, android.view.View, int, long)
    */
   @Override
   public boolean onItemLongClick(AdapterView<?> arg0, View arg1,
     int arg2, long arg3) {
    Log.d(TAG, "onItemLongClick arg2 => " + arg2 + " : arg3 => "
      + arg3);
    return true;
   }
  });

  //
  getListView().setEmptyView(setEmptyItems("EMPTY"));

 }

 /*
  * アイテムの追加
  */
 public void add(String message) {
  Log.d(TAG, "message message" + message);
  mList.add(message);

 }

 /*
  * @see android.support.v4.app.Fragment#onStart()
  */
 public void onStart() {
  super.onStart();
  // getListView().setEmptyView(noItems("EMPTY"));
 }

 /*
  * ListViewにデータが無かった場合に表示するビューの設定
  */
 private TextView setEmptyItems(String text) {

  //
  TextView emptyView = new TextView(getActivity());

  //
  emptyView.setLayoutParams(new LayoutParams(LayoutParams.MATCH_PARENT,
    LayoutParams.MATCH_PARENT));

  // 文字列の設定
  emptyView.setText(text);
  // フォントサイズ
  emptyView.setTextSize(12);
  // 非表示にしておく
  emptyView.setVisibility(View.GONE);
  // 中央配置にする
  emptyView.setGravity(Gravity.CENTER_VERTICAL
    | Gravity.CENTER_HORIZONTAL);

  // ListViewの親Viewに追加する
  ((ViewGroup) getListView().getParent()).addView(emptyView);

  return emptyView;
 }

 /*
  * アイテムのクリック
  * 
  * @see
  * android.support.v4.app.ListFragment#onListItemClick(android.widget.ListView
  * , android.view.View, int, long)
  */
 @Override
 public void onListItemClick(ListView listView, View v, int position, long id) {

  Log.d(TAG, "onListItemClick position => " + position + " : id => " + id);

  // クリックされたアイテムを取得する
  String item = (String) listView.getItemAtPosition(position);

  // アイテムの削除
  mAdapter.remove(item);

  // Adapterの更新
  mAdapter.notifyDataSetChanged();

  // ListViewの再描画
  mListView.invalidateViews();

 }

}

■MainActivity.java

ボタンのクリックにsetListShownを実行して表示、非表示を切り替えています。
※setListShownのほかにsetListShownNoAnimationというメソッドもあります。
package com.example.listfragment4;

import android.os.Bundle;
import android.support.v4.app.FragmentActivity;
import android.support.v4.app.FragmentManager;
import android.support.v4.app.FragmentTransaction;
import android.support.v4.app.ListFragment;
import android.view.Menu;
import android.view.View;
import android.widget.ArrayAdapter;
import android.widget.Button;
import android.view.View.OnClickListener;

public class MainActivity extends FragmentActivity {

 @Override
 protected void onCreate(Bundle savedInstanceState) {
  super.onCreate(savedInstanceState);
  setContentView(R.layout.activity_main);

  // ListFragmentを生成
  final MyListFragment fragment = new MyListFragment();

  // Fragmentを経由してAdapterにデータをセット
  fragment.add("LIST 1");
  fragment.add("LIST 2");
  fragment.add("LIST 3");
  fragment.add("LIST 4");
  fragment.add("LIST 5");
  fragment.add("LIST 6");
  fragment.add("LIST 7");
  fragment.add("LIST 8");
  fragment.add("LIST 9");
  fragment.add("LIST 10");

  // ListFragmentを追加する
  FragmentManager manager = getSupportFragmentManager();
  FragmentTransaction tx = manager.beginTransaction();
  tx.add(R.id.list, fragment, "list_fragment");
  tx.commit();

  Button show = (Button) this.findViewById(R.id.show);
  show.setOnClickListener(new OnClickListener() {

   @Override
   public void onClick(View v) {
    // TODO Auto-generated method stub
    fragment.setListShown(true);
   }

  });

  //
  Button hide = (Button) this.findViewById(R.id.hide);
  hide.setOnClickListener(new OnClickListener() {

   @Override
   public void onClick(View v) {
    // TODO Auto-generated method stub
    fragment.setListShown(false);
   }

  });

 }

 @Override
 public boolean onCreateOptionsMenu(Menu menu) {
  // Inflate the menu; this adds items to the action bar if it is present.
  getMenuInflater().inflate(R.menu.main, menu);
  return true;
 }

}


実行結果は次のようになります。


 非表示を押すとリストが消えてプログレスが表示されます。


以上です(`・ω・´)ゞビシッ!!

気がつけば今年も残り僅か・・・(; ・`д・´)
年越しでAndroidだっ!( ̄ー ̄)bグッ!

参考URL

ListFragmentを使ってみる(ヘッダー、フッター、データが無い場合に特定のViewを表示する)

前回の「ListFragmentを使ってみる(クリック、長押しクリックの設定) 」に
続き今回もListFragmentについて(`・ω・´)シャキーン

今回はリストにフッター、ヘッダーの表示と、
リストにデータが1件も無かった場合に、指定のビューを表示させる方法を試したいと思います。+(0゚・∀・) + ワクテカ +

■AndroidManifest.xml
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.example.listfragment3"
    android:versionCode="1"
    android:versionName="1.0" >

    <uses-sdk
        android:minSdkVersion="8"
        android:targetSdkVersion="17" />

    <application
        android:allowBackup="true"
        android:icon="@drawable/ic_launcher"
        android:label="@string/app_name"
        android:theme="@style/AppTheme" >
        <activity
            android:name="com.example.listfragment3.MainActivity"
            android:label="@string/app_name" >
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />

                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>
    </application>

</manifest>
■activity_main.xml
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@+id/list"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent"
    android:orientation="vertical" >

</LinearLayout>
■MyListFragment.java

ヘッダー、フッターの表示には、
addHeaderViewとaddFooterViewを利用して設定しています。
注意点として、setListAdapterの前に実行しておく必要があります
もし後に実行した場合には、次のようなエラーが発生します(´;ω;`)ウッ…
12-30 16:45:58.624: E/AndroidRuntime(17521): Caused by: java.lang.IllegalStateException: Cannot add header view to list -- setAdapter has already been called. mListView.addFooterView(footer);
また、ViewPagerなどを利用して画面の行き来を行った場合には、
再描画が発生した際にはsetListAdapterにnullを設定してから実行する必要があります。
FragmentPagerAdapterとListFragmentを使ったらはまった
※ただこのやり方でうまく行かないケースもあるかも?
その場合にはaddFooterViewなどは使わずに動的に作成する事で回避が出来るそうです。

データが無かった場合に表示させる設定は、次の箇所で行っています。
getListView().setEmptyView(setEmptyItems("EMPTY"));
※動的じゃなくて静的にxml側で設定する事も可能。

リストをクリックすると、アイテムを削除するようになっているので、
全てのリストを削除する事で、データが無くなった時の表示を確認することが出来ます( ̄ー ̄)ニヤリ
package com.example.listfragment3;

import java.util.ArrayList;

import android.os.Bundle;
import android.support.v4.app.FragmentActivity;
import android.support.v4.app.ListFragment;
import android.util.Log;
import android.view.Gravity;
import android.view.View;
import android.view.ViewGroup;
import android.view.ViewGroup.LayoutParams;
import android.widget.AdapterView;
import android.widget.AdapterView.OnItemLongClickListener;
import android.widget.ArrayAdapter;
import android.widget.LinearLayout;
import android.widget.ListView;
import android.widget.TextView;

public class MyListFragment extends ListFragment {

 private static final String TAG = "MyListFragment";
 //
 private ListView mListView = null;
 //
 private ArrayList<String> mList = new ArrayList<String>();
 private ArrayAdapter<String> mAdapter = null;

 /*
  * 親となるActivityの「onCreate」の終了
  * 
  * @see android.support.v4.app.Fragment#onActivityCreated(android.os.Bundle)
  */
 @Override
 public void onActivityCreated(Bundle savedInstanceState) {
  super.onActivityCreated(savedInstanceState);

  Log.d(TAG, "onActivityCreated");

  // アダプター生成
  mAdapter = new ArrayAdapter<String>(getActivity(),
    android.R.layout.simple_list_item_1, mList);

  FragmentActivity activity = getActivity();

  // ListViewを取得する
  mListView = getListView();

  /*
   * ヘッダーの作成
   * 
   * 大枠のビューに対してsetLayoutParamsを利用すると、
   * Caused by: java.lang.ClassCastException: android.widget.LinearLayout$LayoutParams
   * というエラーが発生してしまう・・・orz
   */
  LinearLayout header = new LinearLayout(activity);
  // 縦に並べる
  header.setOrientation(LinearLayout.VERTICAL);

  // TextViewを生成する
  TextView textView = new TextView(activity);
  // 幅、高さの設定
  LinearLayout.LayoutParams layoutTextView = new LinearLayout.LayoutParams(
    LinearLayout.LayoutParams.MATCH_PARENT,
    LinearLayout.LayoutParams.WRAP_CONTENT);
  textView.setLayoutParams(layoutTextView);
  // 文字の位置の設定
  textView.setGravity(Gravity.CENTER);
  // 文字を設定
  textView.setText("HEADER");
  // フォントサイズ変更
  textView.setTextSize(14.0f);

  // ヘッダーにTextViewを追加する
  header.addView(textView);

  /*
   * フッターの作成
   */
  LinearLayout footer = new LinearLayout(activity);
  // 縦に並べる
  footer.setOrientation(LinearLayout.VERTICAL);

  // TextViewを生成する
  textView = new TextView(activity);
  textView.setLayoutParams(layoutTextView);
  // 文字の位置の設定
  textView.setGravity(Gravity.CENTER);
  // 文字を設定
  textView.setText("FOOTER");
  // フォントサイズ変更
  textView.setTextSize(14.0f);

  // ヘッダーにTextViewを追加する
  footer.addView(textView);

  // setListAdapterの前に設定する
  mListView.addHeaderView(header);
  mListView.addFooterView(footer);

  // アダプターの設定
  setListAdapter(mAdapter);

  //
  mListView.setOnItemLongClickListener(new OnItemLongClickListener() {

   /*
    * アイテムの長押し
    * 
    * @see
    * android.widget.AdapterView.OnItemLongClickListener#onItemLongClick
    * (android.widget.AdapterView, android.view.View, int, long)
    */
   @Override
   public boolean onItemLongClick(AdapterView<?> arg0, View arg1,
     int arg2, long arg3) {
    Log.d(TAG, "onItemLongClick arg2 => " + arg2 + " : arg3 => "
      + arg3);
    return true;
   }
  });

  //データが無かった場合に表示させる設定
  getListView().setEmptyView(setEmptyItems("EMPTY"));

 }

 /*
  * アイテムの追加
  */
 public void add(String message) {
  Log.d(TAG, "message message" + message);
  mList.add(message);

 }

 /*
  * @see android.support.v4.app.Fragment#onStart()
  */
 public void onStart() {
  super.onStart();
  // getListView().setEmptyView(noItems("EMPTY"));
 }

 /*
  * ListViewにデータが無かった場合に表示するビューの設定
  */
 private TextView setEmptyItems(String text) {

  //
  TextView emptyView = new TextView(getActivity());

  //
  emptyView.setLayoutParams(new LayoutParams(LayoutParams.MATCH_PARENT,
    LayoutParams.MATCH_PARENT));

  // 文字列の設定
  emptyView.setText(text);
  // フォントサイズ
  emptyView.setTextSize(12);
  // 非表示にしておく
  emptyView.setVisibility(View.GONE);
  // 中央配置にする
  emptyView.setGravity(Gravity.CENTER_VERTICAL
    | Gravity.CENTER_HORIZONTAL);

  // ListViewの親Viewに追加する
  ((ViewGroup) getListView().getParent()).addView(emptyView);

  return emptyView;
 }

 /*
  * アイテムのクリック
  * 
  * @see
  * android.support.v4.app.ListFragment#onListItemClick(android.widget.ListView
  * , android.view.View, int, long)
  */
 @Override
 public void onListItemClick(ListView listView, View v, int position, long id) {

  Log.d(TAG, "onListItemClick position => " + position + " : id => " + id);

  // クリックされたアイテムを取得する
  String item = (String) listView.getItemAtPosition(position);

  // アイテムの削除
  mAdapter.remove(item);

  // Adapterの更新
  mAdapter.notifyDataSetChanged();

  // ListViewの再描画
  mListView.invalidateViews();

 }

}
■MainActivity.java
package com.example.listfragment3;

import android.os.Bundle;
import android.support.v4.app.FragmentActivity;
import android.support.v4.app.FragmentManager;
import android.support.v4.app.FragmentTransaction;
import android.support.v4.app.ListFragment;
import android.view.Menu;
import android.widget.ArrayAdapter;

public class MainActivity extends FragmentActivity {

 @Override
 protected void onCreate(Bundle savedInstanceState) {
  super.onCreate(savedInstanceState);
  setContentView(R.layout.activity_main);

  // ListFragmentを生成
  MyListFragment fragment = new MyListFragment();

  // Fragmentを経由してAdapterにデータをセット
  fragment.add("LIST 1");
  fragment.add("LIST 2");
  fragment.add("LIST 3");
  fragment.add("LIST 4");
  fragment.add("LIST 5");
  fragment.add("LIST 6");
  fragment.add("LIST 7");
  fragment.add("LIST 8");
  fragment.add("LIST 9");
  fragment.add("LIST 10");

  // ListFragmentを追加する
  FragmentManager manager = getSupportFragmentManager();
  FragmentTransaction tx = manager.beginTransaction();
  tx.add(R.id.list, fragment, "list_fragment");
  tx.commit();

 }

 @Override
 public boolean onCreateOptionsMenu(Menu menu) {
  // Inflate the menu; this adds items to the action bar if it is present.
  getMenuInflater().inflate(R.menu.main, menu);
  return true;
 }

}

実行結果は次のようになります。

上部に、addHeaderViewで設定したビューが表示されます。

下部に、addFooterViewで設定したビューが表示されます。


 リストをクリックしていき、全て消していきます。



全てのデータを消すと、setEmtpyViewで設定したビューが表示されます。

以上です(`・ω・´)ゞビシッ!!

参考URL

2013年12月30日月曜日

ListFragmentを使ってみる(クリック、長押しクリックの設定)

前回の「ListFragmentを使ってみる」に続き今回もListFragmentについて(`・ω・´)シャキーン
今回はリストにクリックイベントを設定したいと思います。

前回はActivity内でListFragmentを生成してAdapterの設定までを行っていましたが、
今回はListFragmentを継承するMyListFragmentを作成して、
そこに設定とクリックイベントの処理を記述していきたいと思います。

■AndroidManifest.xml
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.example.listfragment2"
    android:versionCode="1"
    android:versionName="1.0" >

    <uses-sdk
        android:minSdkVersion="8"
        android:targetSdkVersion="17" />

    <application
        android:allowBackup="true"
        android:icon="@drawable/ic_launcher"
        android:label="@string/app_name"
        android:theme="@style/AppTheme" >
        <activity
            android:name="com.example.listfragment2.MainActivity"
            android:label="@string/app_name" >
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />

                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>
    </application>

</manifest>
■activity_main.xml
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@+id/list"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent"
    android:orientation="vertical" >

</LinearLayout>
■MyListFragment.java

ListFragmentを継承したクラスになります。
Adapterにデータを追加する処理、クリックイベント、長押しイベントの処理などを設定しています。
package com.example.listfragment2;

import java.util.ArrayList;

import android.os.Bundle;
import android.support.v4.app.ListFragment;
import android.util.Log;
import android.view.View;
import android.widget.AdapterView;
import android.widget.AdapterView.OnItemLongClickListener;
import android.widget.ArrayAdapter;
import android.widget.ListView;

public class MyListFragment extends ListFragment {

 private static final String TAG = "MyListFragment";

 private ArrayList<String> mList = new ArrayList<String>();

 /*
  * 親となるActivityの「onCreate」の終了を知らせる
  * @see android.support.v4.app.Fragment#onActivityCreated(android.os.Bundle)
  */
 @Override
 public void onActivityCreated(Bundle savedInstanceState) {
  super.onActivityCreated(savedInstanceState);

  Log.d(TAG, "onActivityCreated");

  // アダプター生成
  ArrayAdapter<String> adapter = new ArrayAdapter<String>(getActivity(),
    android.R.layout.simple_list_item_1, mList);

  // アダプターの設定
  setListAdapter(adapter);

  //
  getListView().setOnItemLongClickListener(new OnItemLongClickListener() {

   /*
    * アイテムの長押し
    * 
    * @see
    * android.widget.AdapterView.OnItemLongClickListener#onItemLongClick
    * (android.widget.AdapterView, android.view.View, int, long)
    */
   @Override
   public boolean onItemLongClick(AdapterView<?> arg0, View arg1,
     int arg2, long arg3) {
    Log.d(TAG, "onItemLongClick arg2 => " + arg2 + " : arg3 => "
      + arg3);
    return true;
   }
  });

 }

 /*
  * アイテムの追加
  */
 public void add(String message) {

  mList.add(message);

 }

 /*
  * アイテムのクリック
  * 
  * @see
  * android.support.v4.app.ListFragment#onListItemClick(android.widget.ListView
  * , android.view.View, int, long)
  */
 @Override
 public void onListItemClick(ListView l, View v, int position, long id) {
  Log.d(TAG, "onListItemClick position => " + position + " : id => " + id);
 }

}

■MainActivity.java
package com.example.listfragment2;

import android.os.Bundle;
import android.support.v4.app.FragmentActivity;
import android.support.v4.app.FragmentManager;
import android.support.v4.app.FragmentTransaction;
import android.support.v4.app.ListFragment;
import android.view.Menu;
import android.widget.ArrayAdapter;

public class MainActivity extends FragmentActivity {

 @Override
 protected void onCreate(Bundle savedInstanceState) {
  super.onCreate(savedInstanceState);
  setContentView(R.layout.activity_main);

  // ListFragmentを生成
  MyListFragment fragment = new MyListFragment();

  // Fragmentを経由してAdapterにデータをセット
  fragment.add("LIST 1");
  fragment.add("LIST 2");
  fragment.add("LIST 3");
  fragment.add("LIST 4");
  fragment.add("LIST 5");
  fragment.add("LIST 6");
  fragment.add("LIST 7");
  fragment.add("LIST 8");
  fragment.add("LIST 9");
  fragment.add("LIST 10");

  // ListFragmentを追加する
  FragmentManager manager = getSupportFragmentManager();
  FragmentTransaction tx = manager.beginTransaction();
  tx.add(R.id.list, fragment, "list_fragment");
  tx.commit();

 }

 @Override
 public boolean onCreateOptionsMenu(Menu menu) {
  // Inflate the menu; this adds items to the action bar if it is present.
  getMenuInflater().inflate(R.menu.main, menu);
  return true;
 }

}

実行結果は次のようになります。


12-30 13:55:46.335: D/MyListFragment(3465): onListItemClick position => 0 : id => 0
12-30 13:55:46.955: D/MyListFragment(3465): onListItemClick position => 1 : id => 1
12-30 13:55:47.405: D/MyListFragment(3465): onListItemClick position => 2 : id => 2
12-30 13:55:48.595: D/MyListFragment(3465): onItemLongClick arg2 => 3 : arg3 => 3

以上です(`・ω・´)ゞビシッ!!

参考URL

ListFragmentを使ってみる

今回はListFragmentを試してみたいと思います(`・ω・´)シャキーン

特に変わったことをしないので、Adapterを用意して設定して終了って感じです(ΦωΦ)フフフ…
■AndroidManifest.xml
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.example.listfragment1"
    android:versionCode="1"
    android:versionName="1.0" >

    <uses-sdk
        android:minSdkVersion="8"
        android:targetSdkVersion="17" />

    <application
        android:allowBackup="true"
        android:icon="@drawable/ic_launcher"
        android:label="@string/app_name"
        android:theme="@style/AppTheme" >
        <activity
            android:name="com.example.listfragment1.MainActivity"
            android:label="@string/app_name" >
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />

                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>
    </application>

</manifest>

■activity_main.xml
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@+id/list"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent"
    android:orientation="vertical" >

</LinearLayout>
■MainActivity.java
package com.example.listfragment1;

import android.os.Bundle;
import android.support.v4.app.FragmentActivity;
import android.support.v4.app.FragmentManager;
import android.support.v4.app.FragmentTransaction;
import android.support.v4.app.ListFragment;
import android.view.Menu;
import android.widget.ArrayAdapter;

public class MainActivity extends FragmentActivity {

 @Override
 protected void onCreate(Bundle savedInstanceState) {
  super.onCreate(savedInstanceState);
  setContentView(R.layout.activity_main);

  // Adapterの生成
  ArrayAdapter<String> adapter = new ArrayAdapter<String>(this,
    android.R.layout.simple_list_item_1);

  // Adapterのデータをセット
  adapter.add("LIST 1");
  adapter.add("LIST 2");
  adapter.add("LIST 3");
  adapter.add("LIST 4");
  adapter.add("LIST 5");
  adapter.add("LIST 6");
  adapter.add("LIST 7");
  adapter.add("LIST 8");
  adapter.add("LIST 9");
  adapter.add("LIST 10");

  // ListFragmentを生成
  ListFragment fragment = new ListFragment();
  // Adapterを設定
  fragment.setListAdapter(adapter);

  // ListFragmentを追加する
  FragmentManager manager = getSupportFragmentManager();
  FragmentTransaction tx = manager.beginTransaction();
  tx.add(R.id.list, fragment, "list_fragment");
  tx.commit();

 }

 @Override
 public boolean onCreateOptionsMenu(Menu menu) {
  // Inflate the menu; this adds items to the action bar if it is present.
  getMenuInflater().inflate(R.menu.main, menu);
  return true;
 }

}

実行結果は次のようになります。

以上です(`・ω・´)ゞビシッ!!

参考URL

レイアウトの階層について(android.R.id.contentなど)

色々とネット上のsampleを見ていると「R.id.content」っていう記述を見かけていましたが、
レイアウト用のxmlにはそのidが振られている記述が無いので、
不思議に思い調べてみると、
内部的に自動でContentViewと呼ばれるビューに割り当てられているidでした(; ・`д・´)

通りでレイアウトのXMLに記述が無いわけですね(゚д゚)(。_。)(゚д゚)(。_。) ウンウン

ContentViewとは、普段onCreateで何気なく使っていたsetContentViewで実行された、
レイアウトビューのことらしいです(´・∀・`)ヘー

ContentViewで設定されたビューの上に、内部的には親ビューとしてFrameLayoutがあるそうです。
このViewに設定されているidが「R.id.content」になっています。

さらにその上に、「DecorView」というビューもあるそうで、
これが実際には、レイアウト階層のルート要素となるそうです。

簡単な階層の関係図を書くと、次のようになります。
DecorView(id無し)
↓
LinearLayout(id無し。全てのビューのルート)
↓
FrameLayout(R.id.content)
↓
ContentView
ContextViewは、次の記述で取得することが可能。
android.R.id.contentは頭にandroidをつけること。

ContextViewの親FrameLayoutの取得方法
ViewGroup contentRoot = (ViewGroup)this.findViewById(android.R.id.content);
or
ViewGroup root = (ViewGroup)getWindow().getDecorView().findViewById(android.R.id.content);
ContentViewの取得(setContentViewで設定したビュー)
View contentView = ((ViewGroup)findViewById(android.R.id.content)).getChildAt(0);
setContentViewがあるのに、getContentViewが無いそうです(´;ω;`)ウッ…

【補足】
全てのビューのルートLinearLayoutの下には、
実際にはFrameLayoutが2つぶら下がっているそうです。

「R.id.content」とは別のFrameLayoutはタイトルバーなどで利用されているものらしいです。
DecorView(id無し)
↓
LinearLayout(id無し。全てのビューのルート)
↓
FrameLayout(id無し)
↓
TextView
次の記述で、TextViewを取得することが可能。
TextView titleBar = (TextView)this.findViewById(android.R.id.title);
タイトルバー、コンテンツのルート共にSDKが内部的にIDを振られているため、直接取得できる

以上です(`・ω・´)ゞビシッ!!

参考URL

2013年12月24日火曜日

ViewPagerを使ってみる(FragmentStatePagerAdapterを利用する)

前回の記事「ViewPagerを使ってみる(FragmentPagerAdapterを利用する) 」では
ViewPagerのFragmentの利用に、FragmentPagerAdapterを利用しましたが、
もう一つAdapterとしてFragmentStatePagerAdapterが用意されているそうです(´・∀・`)ヘー

■FragmentStatePagerAdapterとFragmentPagerAdapterとは違いについて
FragmentStatePagerAdapterは、
必要が無くなったページのFragmentをデタッチするのではなくて削除するPagerAdapterです。

よって、必要がなくなったページは破棄され、FragmentのSavedStateだけが保持されます。
メモリ上に保持されるFragmentの数は制限されるため、大量のページに対して使う場合にも、
メモリを圧迫することがありません。

その代わりに、一度削除したページが再度必要になった場合、
Fragmentのインスタンスを生成し直すため、
FragmentPagerAdapterを使う場合よりも多少遅くなる。
※参考「Android UI Cookbook for 4.0 ICS(Ice Cream Sandwich)アプリ開発術

大量のページをViewPagerで表示したい場合には、「FragmentStatePagerAdapter」で、
表示するページが少ない場合には、「FragmentPagerAdapter」って感じですかね(゚д゚)(。_。)(゚д゚)(。_。) ウンウン

使い方には、前回のソースコードでで、FragmentPagerAdapterだった部分をFragmentStatePagerAdapterに変えるだけでいけます( ´∀`)bグッ!

■AndroidManifest.xml
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.example.viewpager4"
    android:versionCode="1"
    android:versionName="1.0" >

    <uses-sdk
        android:minSdkVersion="8"
        android:targetSdkVersion="18" />

    <application
        android:allowBackup="true"
        android:icon="@drawable/ic_launcher"
        android:label="@string/app_name"
        android:theme="@style/AppTheme" >
        <activity
            android:name="com.example.viewpager4.MainActivity"
            android:label="@string/app_name" >
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />

                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>
    </application>

</manifest>
■activity_main.xml
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:gravity="center_horizontal"
    android:orientation="vertical"
    android:padding="4dip" >

    <android.support.v4.view.ViewPager
        android:id="@+id/pager"
        android:layout_width="match_parent"
        android:layout_height="0px"
        android:layout_weight="1" />

    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:gravity="center"
        android:measureWithLargestChild="true"
        android:orientation="horizontal" >

        <Button
            android:id="@+id/first"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="First" />

        <Button
            android:id="@+id/last"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="Last" />
    </LinearLayout>

</LinearLayout>

■MyFragmentStatePagerAdapter.java
package com.example.viewpager4;

import android.os.Bundle;
import android.support.v4.app.FragmentManager;
import android.support.v4.app.Fragment;
import android.support.v4.app.FragmentPagerAdapter;
import android.support.v4.app.FragmentStatePagerAdapter;

/**
 * FragmentPagerAdapter を継承したクラス
 */
public class MyFragmentStatePagerAdapter extends FragmentStatePagerAdapter {
 
 private String[] pageTitle = { "Page1", "Page2", "Page3" };

 public MyFragmentStatePagerAdapter(FragmentManager fragmentManager) {
  super(fragmentManager);
 }

 @Override
 public Fragment getItem(int position) {

  Fragment fragment = PageFragment.newInstance(position + 1);
  return fragment;

 }

 @Override
 public int getCount() {
  return pageTitle.length;
 }

 @Override
 public CharSequence getPageTitle(int position) {
  return pageTitle[position];
 }

}
■PageFragment.java
package com.example.viewpager4;

import android.os.Bundle;
import android.support.v4.app.Fragment;
import android.view.Gravity;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.LinearLayout;
import android.widget.TextView;

public class PageFragment extends Fragment {
 int mNum;

 public static PageFragment newInstance(int num) {
  PageFragment f = new PageFragment();
  Bundle args = new Bundle();
  args.putInt("pageIndex", num);
  f.setArguments(args);

  return f;
 }

 @Override
 public void onCreate(Bundle savedInstanceState) {
  super.onCreate(savedInstanceState);
  mNum = getArguments() != null ? getArguments().getInt("pageIndex") : 1;
 }

 @Override
 public View onCreateView(LayoutInflater inflater, ViewGroup container,
   Bundle savedInstanceState) {

  // TextViewを生成する
  TextView view = new TextView(getActivity());
  // 幅、高さの設定
  LinearLayout.LayoutParams layout = new LinearLayout.LayoutParams(
    LinearLayout.LayoutParams.MATCH_PARENT,
    LinearLayout.LayoutParams.MATCH_PARENT);
  view.setLayoutParams(layout);
  // 文字の位置の設定
  view.setGravity(Gravity.CENTER);
  // 文字を設定
  view.setText(getArguments().getString("pageIndex"));
  // フォントサイズ変更
  view.setTextSize(180.0f);

  return view;
 }
}
■MainActivity.java
package com.example.viewpager4;

import android.os.Bundle;
import android.support.v4.app.FragmentActivity;
import android.support.v4.app.FragmentManager;
import android.support.v4.view.ViewPager;
import android.view.View;

public class MainActivity extends FragmentActivity {

 @Override
 protected void onCreate(Bundle savedInstanceState) {
  super.onCreate(savedInstanceState);
  setContentView(R.layout.activity_main);

  // FragmentManager を取得
  FragmentManager manager = getSupportFragmentManager();

  // ViewPager のインスタンスを取得
  final ViewPager viewPager = (ViewPager) findViewById(R.id.pager);

  // FragmentPagerAdapter を継承したクラスのアダプターを作成し、ViewPager にセット
  final MyFragmentStatePagerAdapter adapter = new MyFragmentStatePagerAdapter(
    manager);
  //
  viewPager.setAdapter(adapter);

  // First ボタンが押されたら、最初のページを表示
  findViewById(R.id.first).setOnClickListener(new View.OnClickListener() {

   @Override
   public void onClick(View v) {
    viewPager.setCurrentItem(0);
   }
  });

  // Last ボタンが押されたら、最後のページを表示
  findViewById(R.id.last).setOnClickListener(new View.OnClickListener() {

   @Override
   public void onClick(View v) {
    viewPager.setCurrentItem(adapter.getCount() - 1);
   }
  });
 }
}
実行結果は次のようになります。

以上です(`・ω・´)ゞビシッ!!

参考URL

ViewPagerを使ってみる(FragmentPagerAdapterを利用する)

以前にViewPagerを利用しましたが、Fragmentを使っていなかったので、
今後のことも考えてFragmentを利用したものを試したいと思います!Fragmentヽ(´ー`)ノマンセー

Fragmentで利用する場合には、AdapterとしてFragmentPagerAdapterを利用するそうです。

・FragmentPagerAdapterとは
FragmentPagerAdapterは、スワイプ時に各Fragmentをデタッチしますが、メモリ上に保持しておくので、簡単に再度アタッチができる。
(FragmentのonAttach、onCreateが毎回呼び出されるわけではない)
ただし、onCreateViewは呼び出されるため、ラジオボタンやチェックボックスなどの入力状態を保持したい場合には、
onSaveInstanceStateで状態を保存し、onCreateViewでそれを復元する必要がある。

このように、FragmentPagerAdapterは一度生成されたFragmentをメモリ上に保持しておくため、
大量のページに対して使用するとメモリを圧迫することになる。
※大量のページに対してViewPagerを利用する場合には、FragmentStatePagerAdapterを利用すること。
こちらの本を参考にしました。「Android UI Cookbook for 4.0 ICS(Ice Cream Sandwich)アプリ開発術

■AndroidManifest.xml
&lt;?xml version="1.0" encoding="utf-8"?&gt;
&lt;manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.example.viewpager3"
    android:versionCode="1"
    android:versionName="1.0" &gt;

    &lt;uses-sdk
        android:minSdkVersion="8"
        android:targetSdkVersion="18" /&gt;

    &lt;application
        android:allowBackup="true"
        android:icon="@drawable/ic_launcher"
        android:label="@string/app_name"
        android:theme="@style/AppTheme" &gt;
        &lt;activity
            android:name="com.example.viewpager3.MainActivity"
            android:label="@string/app_name" &gt;
            &lt;intent-filter&gt;
                &lt;action android:name="android.intent.action.MAIN" /&gt;

                &lt;category android:name="android.intent.category.LAUNCHER" /&gt;
            &lt;/intent-filter&gt;
        &lt;/activity&gt;
    &lt;/application&gt;

&lt;/manifest&gt;
■activity_main.xml
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:gravity="center_horizontal"
    android:orientation="vertical"
    android:padding="4dip" >

    <android.support.v4.view.ViewPager
        android:id="@+id/pager"
        android:layout_width="match_parent"
        android:layout_height="0px"
        android:layout_weight="1" />

    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:gravity="center"
        android:measureWithLargestChild="true"
        android:orientation="horizontal" >

        <Button
            android:id="@+id/first"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="First" />

        <Button
            android:id="@+id/last"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="Last" />
    </LinearLayout>

</LinearLayout>

■MyFragmentPagerAdapter.java
package com.example.viewpager3;

import android.os.Bundle;
import android.support.v4.app.FragmentManager;
import android.support.v4.app.Fragment;
import android.support.v4.app.FragmentPagerAdapter;

/**
 * FragmentPagerAdapter を継承したクラス
 */
public class MyFragmentPagerAdapter extends FragmentPagerAdapter {
 
 private String[] pageTitle = { "Page1", "Page2", "Page3" };

 public MyFragmentPagerAdapter(FragmentManager fragmentManager) {
  super(fragmentManager);
 }

 @Override
 public Fragment getItem(int position) {

  // 選択されたページ内のFragmentを生成する
  Fragment fragment = PageFragment.newInstance(position + 1);
  return fragment;

 }

 @Override
 public int getCount() {
  return pageTitle.length;
 }

 @Override
 public CharSequence getPageTitle(int position) {
  return pageTitle[position];
 }

}
■PageFragment.java
package com.example.viewpager3;

import android.os.Bundle;
import android.support.v4.app.Fragment;
import android.view.Gravity;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.LinearLayout;
import android.widget.TextView;

public class PageFragment extends Fragment {

 int mNum;

 public static PageFragment newInstance(int num) {
  PageFragment f = new PageFragment();
  Bundle args = new Bundle();
  args.putInt("pageIndex", num);
  f.setArguments(args);

  return f;
 }

 @Override
 public void onCreate(Bundle savedInstanceState) {
  super.onCreate(savedInstanceState);
  mNum = getArguments() != null ? getArguments().getInt("pageIndex") : 1;
 }

 @Override
 public View onCreateView(LayoutInflater inflater, ViewGroup container,
   Bundle savedInstanceState) {

  // TextViewを生成する
  TextView view = new TextView(getActivity());
  // 幅、高さの設定
  LinearLayout.LayoutParams layout = new LinearLayout.LayoutParams(
    LinearLayout.LayoutParams.MATCH_PARENT,
    LinearLayout.LayoutParams.MATCH_PARENT);
  view.setLayoutParams(layout);
  // 文字の位置の設定
  view.setGravity(Gravity.CENTER);
  // 文字を設定
  view.setText(String.valueOf(getArguments().getInt("pageIndex")));
  // フォントサイズ変更
  view.setTextSize(180.0f);

  return view;
 }
}
■MainActivity.java
package com.example.viewpager3;

import android.support.v4.app.FragmentManager;
import android.os.Bundle;
import android.support.v4.app.FragmentActivity;
import android.support.v4.view.ViewPager;
import android.view.View;

public class MainActivity extends FragmentActivity {

 @Override
 protected void onCreate(Bundle savedInstanceState) {
  super.onCreate(savedInstanceState);
  setContentView(R.layout.activity_main);

  // FragmentManager を取得
  FragmentManager manager = getSupportFragmentManager();

  // ViewPager のインスタンスを取得
  final ViewPager viewPager = (ViewPager) findViewById(R.id.pager);

  // FragmentPagerAdapter を継承したクラスのアダプターを作成し、ViewPager にセット
  final MyFragmentPagerAdapter adapter = new MyFragmentPagerAdapter(
    manager);
  viewPager.setAdapter(adapter);

  // First ボタンが押されたら、最初のページを表示
  findViewById(R.id.first).setOnClickListener(new View.OnClickListener() {

   @Override
   public void onClick(View v) {
    viewPager.setCurrentItem(0);
   }
  });

  // Last ボタンが押されたら、最後のページを表示
  findViewById(R.id.last).setOnClickListener(new View.OnClickListener() {

   @Override
   public void onClick(View v) {
    viewPager.setCurrentItem(adapter.getCount() - 1);
   }
  });
 }
}

実行結果は次のようになります。

以上です(`・ω・´)ゞビシッ!!

参考URL

2013年12月23日月曜日

ListView、GridViewなどのsetEmptyViewについて

昨日、本屋さんに行ってAndroidの本を立ち読みしていたら、
setEmptyViewというものが載っていたので、どういうものか試してみました(ΦωΦ)フフフ…

ListViewやGridViewなどで利用可能とのことなので、
各要素にデータが無かった場合に、代わりに表示してくれるViewが設定できるのかと思いきや、
実際には、ListViewやGridViewにデータが1つも無かった場合に、
それらのViewの代わりに表示するViewを設定できるものみたいです。

内部的には、ListViewとsetEmptyViewで指定されたViewは、
Visibility を View.GONE と View.VISIBLEを利用して切り替えられているそうです。

ListViewのヘッダー・フッターを利用する時の注意点として、次のものがあるそうです
Android ListView でデータが空のときもヘッダー・フッターを表示する
・ListFragment には setEmptyText() という、データが空のときに表示する文字をセットするメソッドが用意されています。
このメソッドが呼ばれると、次のように ListView の setEmptyView() が呼ばれます。

ListViewの各要素をクリックしたところが消えるサンプルで挙動を確認してみます。
全てのリストを消すと、setEmptyViewが表示されるようになります。

■AndroidManifest.xml
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.example.listview2"
    android:versionCode="1"
    android:versionName="1.0" >

    <uses-sdk
        android:minSdkVersion="8"
        android:targetSdkVersion="17" />

    <application
        android:allowBackup="true"
        android:icon="@drawable/ic_launcher"
        android:label="@string/app_name"
        android:theme="@style/AppTheme" >
        <activity
            android:name="com.example.listview2.MainActivity"
            android:label="@string/app_name" >
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />

                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>
    </application>

</manifest>
■activity_main.xml
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:paddingBottom="@dimen/activity_vertical_margin"
    android:paddingLeft="@dimen/activity_horizontal_margin"
    android:paddingRight="@dimen/activity_horizontal_margin"
    android:paddingTop="@dimen/activity_vertical_margin"
    tools:context=".MainActivity" >

    <ListView
        android:id="@+id/list"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_alignParentTop="true"
        android:layout_centerHorizontal="true" >
    </ListView>

    <!-- ListViewにデータが無かった場合に表示する -->
    <TextView
        android:id="@+id/emptyView"
        android:layout_width="fill_parent"
        android:layout_height="wrap_content"
        android:text="データがありません。" />

</RelativeLayout>
■MainActivity.java
package com.example.listview2;

import java.util.ArrayList;

import android.app.Activity;
import android.os.Bundle;
import android.view.Menu;
import android.view.View;
import android.widget.AdapterView;
import android.widget.ArrayAdapter;
import android.widget.ListView;
import android.widget.TextView;

public class MainActivity extends Activity {

 @Override
 protected void onCreate(Bundle savedInstanceState) {
  super.onCreate(savedInstanceState);
  setContentView(R.layout.activity_main);

  // ListViewのアダプターを生成
  ArrayList<String> data = new ArrayList<String>();
  data.add("リスト1");
  data.add("リスト2");
  data.add("リスト3");
  //
  final ArrayAdapter<String> adapter = new ArrayAdapter<String>(this,
    android.R.layout.simple_list_item_1, data);

  // ListViewを取得する
  ListView list = (ListView) findViewById(R.id.list);

  // データが無かった場合に表示するViewを設定する
  list.setEmptyView(findViewById(R.id.emptyView));

  // アダプターの設定
  list.setAdapter(adapter);

  // ListViewの各要素にクリックイベントを設定する
  list.setOnItemClickListener(new AdapterView.OnItemClickListener() {
   public void onItemClick(AdapterView<?> av, View view, int position,
     long id) {
    // クリックされた要素は削除する
    adapter.remove((String) ((TextView) view).getText());
   }
  });

 }

 @Override
 public boolean onCreateOptionsMenu(Menu menu) {
  // Inflate the menu; this adds items to the action bar if it is present.
  getMenuInflater().inflate(R.menu.main, menu);
  return true;
 }

}
実行結果は次のようになります。


リストをクリックして全て消すと、次のように表示されます。



以上です(`・ω・´)ゞビシッ!!

参考URL

ActionBarを使ってみる(ActionProvider+PopupMenu Android 2.2以上)

前回の「ActionBarを使ってみる(ActionProvider Android 2.2以上) 」で、
ActionProviderのサブメニューを利用して表示の方を行いましたが、
Android 2系と3系以上だと表示が若干違ったので、
どうにか3系と同じ見た目に出来ないかと探していたら、
PopupMenuというものを見つけました!(`・ω・´)シャキーン

これを使えばAndroid 2系でも同じような表示が出来るんじゃないかと思い試してみました。
PopupMenuはAPI Level 11以上から利用可能なので、
Android 2系ではサポートライブラリーを使わないといけません(´;ω;`)ブワッ

■AndroidManifest.xml
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.example.actionbar10"
    android:versionCode="1"
    android:versionName="1.0" >

    <uses-sdk
        android:minSdkVersion="8"
        android:targetSdkVersion="18" />

    <application
        android:allowBackup="true"
        android:icon="@drawable/ic_launcher"
        android:label="@string/app_name"
        android:theme="@style/Theme.AppCompat.Light" >
        <activity
            android:name="com.example.actionbar10.MainActivity"
            android:label="@string/app_name" >
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />

                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>
    </application>

</manifest>
■res/menu/main.xml

オプションメニューの画面レイアウト。
Android 2系で、ActionBarにオプションメニューを表示するためには、 名前空間の「xmlns:myapp="http://schemas.android.com/apk/res-auto"」を忘れずに記述する事。
また、actionProviderClassでは、先ほど追加した名前空間を利用する事。
※Android 2系の記述で書いておけばそれ以降のバージョンでも動作する。

<?xml version="1.0" encoding="utf-8"?>
<menu xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:myapp="http://schemas.android.com/apk/res-auto" >

    <item
        android:id="@+id/menu_custom_action_provider"
        android:showAsAction="ifRoom"
        android:title="Custom action provider"
        myapp:actionProviderClass="com.example.actionbar10.SimpleActionProvider"
        myapp:showAsAction="always"/>
    <item
        android:id="@+id/action_settings1"
        android:orderInCategory="100"
        android:showAsAction="ifRoom"
        android:title="@string/action_settings"/>
    <item
        android:id="@+id/action_settings2"
        android:orderInCategory="100"
        android:showAsAction="ifRoom"
        android:title="@string/action_settings"/>
</menu>
■res/menu/popupmenu.xml

ActionProviderを設定したオプションメニューをクリックした時に
表示されるメニューのレイアウトになります。

画面からはみ出す場合にはどういう見た目になるか確認の為、
無駄に長くしてあります(; ・`д・´)

<?xml version="1.0" encoding="utf-8"?>
<menu xmlns:android="http://schemas.android.com/apk/res/android" >

    <item
        android:id="@+id/Settings1"
        android:title="Settings1">
    </item>
    <item
        android:id="@+id/Settings2"
        android:title="Settings2">
    </item>
    <item
        android:id="@+id/Settings3"
        android:title="Settings3">
    </item>
    <item
        android:id="@+id/Settings4"
        android:title="Settings4">
    </item>
    <item
        android:id="@+id/Settings5"
        android:title="Settings5">
    </item>
    <item
        android:id="@+id/Settings6"
        android:title="Settings6">
    </item>
    <item
        android:id="@+id/Settings7"
        android:title="Settings7">
    </item>
    <item
        android:id="@+id/Settings8"
        android:title="Settings8">
    </item>
    <item
        android:id="@+id/Settings9"
        android:title="Settings9">
    </item>
    <item
        android:id="@+id/Settings10"
        android:title="Settings10">
    </item>
    <item
        android:id="@+id/Settings11"
        android:title="Settings11">
    </item>
    <item
        android:id="@+id/Settings12"
        android:title="Settings12">
    </item>
    <item
        android:id="@+id/Settings13"
        android:title="Settings13">
    </item>
    <item
        android:id="@+id/Settings14"
        android:title="Settings14">
    </item>
    <item
        android:id="@+id/Settings15"
        android:title="Settings15">
    </item>
    <item
        android:id="@+id/Settings16"
        android:title="Settings16">
    </item>
    <item
        android:id="@+id/Settings17"
        android:title="Settings17">
    </item>
    <item
        android:id="@+id/Settings18"
        android:title="Settings18">
    </item>

</menu>
■activity_main.xml
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:paddingBottom="@dimen/activity_vertical_margin"
    android:paddingLeft="@dimen/activity_horizontal_margin"
    android:paddingRight="@dimen/activity_horizontal_margin"
    android:paddingTop="@dimen/activity_vertical_margin"
    tools:context=".MainActivity" >

    <TextView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="@string/hello_world" />

</RelativeLayout>
■SimpleActionProvider.java

ActionProvider内にPopupMenuを生成する処理を記述してあります。

package com.example.actionbar10;

import android.app.Activity;
import android.content.Context;
import android.support.v4.view.ActionProvider;
import android.support.v7.widget.PopupMenu;
import android.support.v7.widget.PopupMenu.OnDismissListener;
import android.support.v7.widget.PopupMenu.OnMenuItemClickListener;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.MenuItem;
import android.view.View;

public class SimpleActionProvider extends ActionProvider {

 private static final String TAG = "SimpleActionProvider";
 private Context mContext;
 private PopupMenu mPopupMenu;

 // ポップアップメニューのアイテムがクリックされた時に呼ばれるイベントリスナ
 private OnMenuItemClickListener mItemClickListener = new OnMenuItemClickListener() {

  @Override
  public boolean onMenuItemClick(MenuItem item) {
   // TODO Auto-generated method stub
   Log.d("OnMenuItemClickListener",
     "onMenuItemClick id => " + item.getItemId()
       + " : title => " + item.getTitle());

   switch (item.getItemId()) {
   // クリックされたオプションメニューのidが「menu_custom_action_provider」だった場合
   case R.id.Settings1:
    Log.d("OnMenuItemClickListener", "click Settings1");
    break;
   case R.id.Settings2:
    Log.d("OnMenuItemClickListener", "click Settings2");
    break;
   }

   return false;
  }

 };
 // ポップアップメニューが非表示になる時に呼ばれるイベントリスナ
 private OnDismissListener mDismissListener = new OnDismissListener() {

  @Override
  public void onDismiss(PopupMenu arg0) {
   // TODO Auto-generated method stub
   Log.d("OnDismissListener", "onDismiss");
  }

 };

 public SimpleActionProvider(Context context) {
  super(context);
  Log.d("SimpleActionProvider", "SimpleActionProvider");
  // TODO Auto-generated constructor stub
  mContext = context;
 }

 /*
  * MenuItemが作成されるタイミングで呼ばれ、作成されるMenuItemに対して何か変更を加える(例えばある条件の場合だけ背景画像を変えるなど)
  * 場合に戻り値として表示させたいViewクラスのオブジェクトを指定すると、ActionBarに戻り値で返したViewが表示されるようになります
  * 
  * @see android.support.v4.view.ActionProvider#onCreateActionView()
  */
 @Override
 public View onCreateActionView() {

  Log.d("SimpleActionProvider", "onCreateActionView");

  // LayoutInflater を取得
  LayoutInflater layoutInflater = LayoutInflater.from(mContext);

  /*
   * popupmenuで表示されるviewに対して何かイベントなどを設定したい場合にはここで設定する
   */

  return null;
 }

 /*
  * popupmenuの生成と表示
  */
 public void showPopupMenu(Activity activity) {

  Log.d("SimpleActionProvider", "showPopupMenuEx");

  // メニューからpopupmenuを表示させるオプションメニューのIDを取得する
  View menuItemView = activity
    .findViewById(R.id.menu_custom_action_provider);

  // popupmenuをインスタンス化
  PopupMenu popupMenu = new PopupMenu(mContext, menuItemView);
  // xmlからviewを生成する
  popupMenu.inflate(R.menu.popupmenu);
  // ポップアップメニューのアイテムがクリックされた時に呼ばれるイベントリスナを取得する
  popupMenu.setOnMenuItemClickListener(mItemClickListener);
  // ポップアップメニューが非表示になる時に呼ばれるイベントリスナを設定する
  popupMenu.setOnDismissListener(mDismissListener);
  //
  popupMenu.show();

 }

}


■MainActivity.java

注意点として、前回の記事にも書きましたが、
Android 2系と、Android 3.0以上のもので次の点が違うので気をつける必要があります。
※Android 2系の記述で書いておけばそれ以降のバージョンでも動作する。

Android 2系の場合について。
・「MenuItem.getActionProvider()」は「MenuItemCompat.getActionProvider(MenuItem)」に書き直す。
・「MenuItem.setActionProvider(actionProvider)」は「MenuItemCompat.setActionProvider(MenuItem,actionProvider)」に書き直す。
・「MenuInflater」は「SupportMenuInflater」に書き直す。

package com.example.actionbar10;

import com.example.actionbar10.SimpleActionProvider;

import android.os.Bundle;
import android.support.v4.view.MenuItemCompat;
import android.support.v7.app.ActionBar;
import android.support.v7.app.ActionBarActivity;
import android.support.v7.widget.PopupMenu;
import android.support.v7.widget.PopupMenu.OnDismissListener;
import android.support.v7.widget.PopupMenu.OnMenuItemClickListener;
import android.util.Log;
import android.view.Menu;
import android.view.MenuItem;

public class MainActivity extends ActionBarActivity {

 private static final String TAG = "MainActivity";

 // ポップアップメニューのアイテムがクリックされた時に呼ばれるイベントリスナ
 private OnMenuItemClickListener mItemClickListener = new OnMenuItemClickListener() {

  @Override
  public boolean onMenuItemClick(MenuItem item) {
   // TODO Auto-generated method stub
   Log.d("OnMenuItemClickListener",
     "onMenuItemClick id => " + item.getItemId()
       + " : title => " + item.getTitle());

   switch (item.getItemId()) {
   // クリックされたオプションメニューのidが「menu_custom_action_provider」だった場合
   case R.id.Settings1:
    Log.d("OnMenuItemClickListener", "click Settings1");
    break;
   case R.id.Settings2:
    Log.d("OnMenuItemClickListener", "click Settings2");
    break;
   }

   return false;
  }

 };
 // ポップアップメニューが非表示になる時に呼ばれるイベントリスナ
 private OnDismissListener mDismissListener = new OnDismissListener() {

  @Override
  public void onDismiss(PopupMenu arg0) {
   // TODO Auto-generated method stub
   Log.d("OnDismissListener", "onDismiss");
  }

 };

 @Override
 public void onCreate(Bundle savedInstanceState) {
  super.onCreate(savedInstanceState);
  setContentView(R.layout.activity_main);

  // action bar を取得する
  ActionBar ab = getSupportActionBar();

 }

 /*
  * メニューが生成される際に起動される。この中でメニューのアイテムを追加したりする。
  * 
  * @see android.app.Activity#onCreateOptionsMenu(android.view.Menu)
  */
 @Override
 public boolean onCreateOptionsMenu(Menu menu) {

  // xmlからメニューを生成する
  getMenuInflater().inflate(R.menu.main, menu);

  return super.onCreateOptionsMenu(menu);

 }

 /*
  * オプションメニューがクリックされたら
  * 
  * @see android.app.Activity#onOptionsItemSelected(android.view.MenuItem)
  */
 @Override
 public boolean onOptionsItemSelected(MenuItem item) {

  Log.d(TAG, "onOptionsItemSelected title => " + item.getTitle());

  switch (item.getItemId()) {
  // クリックされたオプションメニューのidが「menu_custom_action_provider」だった場合
  case R.id.menu_custom_action_provider:

   // ActionProviderを取得する
   SimpleActionProvider actionProvider = (SimpleActionProvider) MenuItemCompat
     .getActionProvider(item);

   // popupmenuを表示する
   actionProvider.showPopupMenu(this);

  }

  return super.onOptionsItemSelected(item);

 }

}

実行結果は次のようになります。
オプションメニューをクリックすると次のように表示されます。
前回だとAndroid 2系と、3系以上で見え方に結構違いがありましが、
PopupMenuを利用する事で似たような表示にすることが出来ましたワーイヽ(゚∀゚)メ(゚∀゚)メ(゚∀゚)ノワーイ

以上です(`・ω・´)ゞビシッ!!

参考URL

2013年12月20日金曜日

ActionBarを使ってみる(ActionProvider Android 2.2以上)

ActionBarのオプションメニューの動作を操作するように、ActionProviderというものが用意されています。
前回の「ActionBarを使ってみる(SearchViewを配置する Android 2.2以上) 」で
行ったActionBarの中にSearchViewとの違いは、
見え方だけではなく、メニューアイテムのデフォルトイベントも処理できるという点らしいです。

2系で実行したい場合には、次の点を気をつける必要があるみたいです。
android.support.v4.view.ActionProviderから抜粋
・メニューリソースにてルート要素に「xmlns:app="http://schemas.android.com/apk/res-auto"」を追加。
・メニューリソースにて「android:actionProviderClass='hogehoge'」は「app:actionProviderClass='hogehoge'」に書き直す。
・「MenuItem.getActionProvider()」は「MenuItemCompat.getActionProvider(MenuItem)」に書き直す。
・「MenuItem.setActionProvider(actionProvider)」は「MenuItemCompat.setActionProvider(MenuItem,actionProvider)」に書き直す。
・「MenuInflater」は「SupportMenuInflater」に書き直す。 *1

■AndroidManifest.xml
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.example.actionbar9"
    android:versionCode="1"
    android:versionName="1.0" >

    <uses-sdk
        android:minSdkVersion="8"
        android:targetSdkVersion="18" />

    <application
        android:allowBackup="true"
        android:icon="@drawable/ic_launcher"
        android:label="@string/app_name"
        android:theme="@style/Theme.AppCompat.Light" >
        <activity
            android:name="com.example.actionbar9.MainActivity"
            android:label="@string/app_name"
            android:uiOptions="splitActionBarWhenNarrow" >
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />

                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>
    </application>

</manifest>
■res/menu/main.xml

オプションメニューの画面レイアウト。
Android 2系で、ActionBarにオプションメニューを表示するためには、 名前空間の「xmlns:myapp="http://schemas.android.com/apk/res-auto"」を忘れずに記述する事。
また、actionProviderClassでは、先ほど追加した名前空間を利用する事。
※Android 2系の記述で書いておけばそれ以降のバージョンでも動作する。

<?xml version="1.0" encoding="utf-8"?>
<menu xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:myapp="http://schemas.android.com/apk/res-auto" >

    <item
        android:id="@+id/menu_custom_action_provider"
        android:showAsAction="ifRoom"
        android:title="Custom action provider"
        myapp:actionProviderClass="com.example.actionbar9.SimpleActionProvider"
        myapp:showAsAction="always"/>

</menu>
■res/menu/provider_menu.xml

オプションメニューをクリックした時に表示される画面レイアウト。

<?xml version="1.0" encoding="utf-8"?>
<menu xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:myapp="http://schemas.android.com/apk/res-auto" >

    <item
        android:id="@+id/item1"
        android:icon="@android:drawable/ic_menu_compass"
        android:title="sub1">
    </item>
    <item
        android:id="@+id/item2"
        android:icon="@android:drawable/ic_menu_camera"
        android:title="sub2">
    </item>

</menu>
■activity_main.xml
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:paddingBottom="@dimen/activity_vertical_margin"
    android:paddingLeft="@dimen/activity_horizontal_margin"
    android:paddingRight="@dimen/activity_horizontal_margin"
    android:paddingTop="@dimen/activity_vertical_margin"
    tools:context=".MainActivity" >

    <TextView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="@string/hello_world" />

</RelativeLayout>

■SimpleActionProvider.java
ActionProviderを継承したクラスになります。

package com.example.actionbar9;

import android.content.Context;
import android.support.v4.view.ActionProvider;
import android.util.Log;
import android.view.MenuInflater;
import android.view.MenuItem;
import android.view.MenuItem.OnMenuItemClickListener;
import android.view.SubMenu;
import android.view.View;
import android.widget.Toast;

public class SimpleActionProvider extends ActionProvider implements
  OnMenuItemClickListener {

 private static final String TAG = "SimpleActionProvider";
 private Context mContext;

 public SimpleActionProvider(Context context) {
  super(context);
  // TODO Auto-generated constructor stub
  this.mContext = context;
 }

 /*
  * MenuItemが作成されるタイミングで呼ばれ、作成されるMenuItemに対して何か変更を加える(例えばある条件の場合だけ背景画像を変えるなど)
  * 場合に戻り値として表示させたいViewクラスのオブジェクトを指定すると、ActionBarに戻り値で返したViewが表示されるようになります
  * 
  * @see android.support.v4.view.ActionProvider#onCreateActionView()
  */
 @Override
 public View onCreateActionView() {
  return null;
 }

 /*
  * デフォルトのアクションターゲットがタップされた時に呼びされる。
  * アクティビティやフラグメントがonOptionsItemSelectedをオーバーライドしているか
  * 、アクションプロバイダーがサブメニューを実装している場合には呼び出されない。
  * 
  * @see android.support.v4.view.ActionProvider#onPerformDefaultAction()
  */
 @Override
 public boolean onPerformDefaultAction() {
  Toast.makeText(mContext, "onPerformDefaultAction", Toast.LENGTH_SHORT)
    .show();
  return super.onPerformDefaultAction();
 }

 /*
  * サブメニューがあることを伝えるためにhasSunMenu()ではtrueを返します
  * 
  * @see android.support.v4.view.ActionProvider#hasSubMenu()
  */
 @Override
 public boolean hasSubMenu() {
  return true;
 }

 /*
  * メニュー表示のたびにonPrepareSubMenu()が呼ばれるので、そこでサブメニューを作成
  * 
  * @see
  * android.support.v4.view.ActionProvider#onPrepareSubMenu(android.view.
  * SubMenu)
  */
 @Override
 public void onPrepareSubMenu(SubMenu subMenu) {

  // クリアしないとサブメニューがどんどん追加されてしまう。
  subMenu.clear();
  MenuInflater inflator = new MenuInflater(mContext);
  inflator.inflate(R.menu.provider_menu, subMenu);
  //
  for (int i = 0; i < subMenu.size(); ++i) {

   // サブメニューのアイテムを取得する
   MenuItem item = subMenu.getItem(i);

   // タイトルを設定
   item.setTitle("メニュー" + String.valueOf(i));

   // 各アイテムのクリックイベントを設定する
   item.setOnMenuItemClickListener(this);

  }
 }

 /*
  * サブメニューがクリックされたら
  * 
  * @see
  * android.view.MenuItem.OnMenuItemClickListener#onMenuItemClick(android
  * .view.MenuItem)
  */
 @Override
 public boolean onMenuItemClick(MenuItem item) {
  // TODO Auto-generated method stub

  String title = (String) item.getTitle();

  Log.d(TAG, "onMenuItemClick " + title);

  return false;
 }
}
■MainActivity.java

注意点として、上記にも書いてありますが、
Android 2系と、Android 3.0以上のもので次の点が違うので気をつける必要があります。
※Android 2系の記述で書いておけばそれ以降のバージョンでも動作する。

Android 2系の場合について。
・「MenuItem.getActionProvider()」は「MenuItemCompat.getActionProvider(MenuItem)」に書き直す。
・「MenuItem.setActionProvider(actionProvider)」は「MenuItemCompat.setActionProvider(MenuItem,actionProvider)」に書き直す。
・「MenuInflater」は「SupportMenuInflater」に書き直す。

package com.example.actionbar9;

import android.os.Bundle;
import android.support.v4.view.MenuItemCompat;
import android.support.v7.app.ActionBar;
import android.support.v7.app.ActionBarActivity;
import android.view.Menu;
import android.view.MenuItem;
import android.widget.Toast;

import com.example.actionbar9.SimpleActionProvider;

public class MainActivity extends ActionBarActivity {

 @Override
 public void onCreate(Bundle savedInstanceState) {
  super.onCreate(savedInstanceState);
  setContentView(R.layout.activity_main);

  // action bar を取得する
  ActionBar ab = getSupportActionBar();

 }

 /*
  * メニューが生成される際に起動される。この中でメニューのアイテムを追加したりする。
  * 
  * 
  * @see android.app.Activity#onCreateOptionsMenu(android.view.Menu)
  */
 @Override
 public boolean onCreateOptionsMenu(Menu menu) {

  // メニューインフレーターを取得して、xmlのリソースファイルを使用してメニューにアイテムを追加
  getMenuInflater().inflate(R.menu.main, menu);

  // ItemのProviderを取得
  MenuItem item = menu.findItem(R.id.menu_custom_action_provider);

  // ActionProviderを継承したクラスをインスタンス化
  SimpleActionProvider actionProvider = new SimpleActionProvider(this);

  // 2系の場合
  MenuItemCompat.setActionProvider(item, actionProvider);

  return super.onCreateOptionsMenu(menu);

 }

 /*
  * オプションメニューがクリックされたら
  * 
  * @see android.app.Activity#onOptionsItemSelected(android.view.MenuItem)
  */
 @Override
 public boolean onOptionsItemSelected(MenuItem item) {
  Toast.makeText(this, item.getTitle() + " is selected",
    Toast.LENGTH_SHORT).show();
  return super.onOptionsItemSelected(item);
 }

}
実行結果は次のようになります。


ActionBarのオプションメニューをクリックすると、次のような画面が表示されます。

同じソースコードでAndroid 4.0のエミュレーターでやってみたら、
次のような見た目で表示されてました(´・∀・`)ヘー


以上です(`・ω・´)ゞビシッ!!

参考URL

2013年12月18日水曜日

ActionBarを使ってみる(オプションメニュー Android 2.2以上)

Android 3.0(API level 11)からActionBarから追加され、
オプションメニューもActionBarを利用している場合には、
ActionBarの中に表示されるようになったそうです。

オプションメニューがActionBarに収まる場合にはActionBar何に全て表示されますが、
多い場合には、オーバーフローメニューとして表示されるようになっているそうです。
※端末に物理的にメニューボタンがある場合には、オーバーフローメニューは表示されない

また、オプションメニューをActionBarの中でどのように表示するからある程度制御する事も可能になっています。

今回は、とりあえずそのまま表示してみます。

■AndroidManifest.xml
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.example.actionbar8"
    android:versionCode="1"
    android:versionName="1.0" >

    <uses-sdk
        android:minSdkVersion="8"
        android:targetSdkVersion="18" />

    <application
        android:allowBackup="true"
        android:icon="@drawable/ic_launcher"
        android:label="@string/app_name"
        android:theme="@style/Theme.AppCompat.Light" >
        <activity
            android:name="com.example.actionbar8.MainActivity"
            android:label="@string/app_name" >
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />

                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>
    </application>

</manifest>
■res/menu/main.xml

オプションメニューの定義になります。
ここで気をつけない点として、
Android 2系で利用する場合には、
名前空間として次のものを登録する必要があります。

xmlns:myapp="http://schemas.android.com/apk/res-auto"
ActionBarでオプションメニューをどのように表示させるかという
showAsAction属性値がAndroid 3.0(API level 11)から導入されたために
Android 3.0(API level 11)未満の場合には必要となります。
Android 3.0以上であればこの名前空間は必要ない。

・showAsAction属性値について
ifRoom
 Actionbarに領域がある場合は表示
withText
 テキストとアイコンの両方を表示(領域がある場合は)
never
 Actionbarに表示しない
always
 常に表示
collapseActionView
 android:actionViewLayout属性で定義されているアクションビューを展開する
 (API Level 14から利用可能)
 action viewを関連付けることで折り畳めるメニューを表示(Level 14から)
 
 最初はオプションメニューボタン表示だけど、オプションメニューをクリックすると、
 actionViewLayoutで指定したViewが表示されるようになる。

showAsActionの条件が複数ある場合にはパイプでつなげる事。
「always|collapseActionView」

・orderInCategory
メニューアイテムの重み付け。複数のメニューアイテムがあるとき数値が大きい方が後に表示される。
<?xml version="1.0" encoding="utf-8"?>
<menu xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:myapp="http://schemas.android.com/apk/res-auto" >

    <item
        android:id="@+id/menu_edit"
        android:icon="@android:drawable/ic_menu_edit"
        android:orderInCategory="1"
        android:title="Edit"
        myapp:showAsAction="ifRoom"/>
    <item
        android:id="@+id/menu_delete"
        android:icon="@android:drawable/ic_menu_delete"
        android:orderInCategory="3"
        android:title="Delete"
        myapp:showAsAction="ifRoom"/>
    <item
        android:id="@+id/menu_save"
        android:icon="@android:drawable/ic_menu_save"
        android:orderInCategory="2"
        android:title="Save"
        myapp:showAsAction="ifRoom"/>

</menu>
■activity_main.xml
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:paddingBottom="@dimen/activity_vertical_margin"
    android:paddingLeft="@dimen/activity_horizontal_margin"
    android:paddingRight="@dimen/activity_horizontal_margin"
    android:paddingTop="@dimen/activity_vertical_margin"
    tools:context=".MainActivity" >

    <TextView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="@string/hello_world" />

</RelativeLayout>

■MainActivity.java
package com.example.actionbar8;

import android.os.Bundle;
import android.app.Activity;
import android.support.v7.app.ActionBarActivity;
import android.view.Menu;
import android.view.MenuInflater;
import android.view.MenuItem;
import android.widget.Toast;

public class MainActivity extends ActionBarActivity {

 @Override
 public void onCreate(Bundle savedInstanceState) {
  super.onCreate(savedInstanceState);
  setContentView(R.layout.activity_main);
 }

 @Override
 public boolean onCreateOptionsMenu(Menu menu) {
  MenuInflater inflater = getMenuInflater();
  inflater.inflate(R.menu.main, menu);
  return true;
 }

 /*
  * オプションメニューがクリックされたら
  * @see android.app.Activity#onOptionsItemSelected(android.view.MenuItem)
  */
 @Override
 public boolean onOptionsItemSelected(MenuItem item) {
  Toast.makeText(this, item.getTitle() + " is selected",
    Toast.LENGTH_SHORT).show();
  return super.onOptionsItemSelected(item);
 }

}
実行結果は次のようになります。



 
ActionBarに収まらない場合には、今まで通りのメニューボタンで残りが表示されます。



以上です(`・ω・´)ゞビシッ!!

参考URL

ActionBarを使ってみる(2系とそれ以外の互換性メモ)

ActionBarを使ってバージョンの2系を中心に開発を行っていて、
4系でも動くか確認してみたら次のようなエラーが発生ガ━━(;゚Д゚)━━ン!!

原因がなかなか分からなかったですけど、
恐らくマニフェストのandroid:themeの記述がダメみたいでした:(;゙゚'ω゚'):
■styles.xml

styles.xmlでAppBaseThemeにActionBarを利用する為に、
「Theme.AppCompat.Light」を指定して、マニフェスト側でそれを指定して使う。
<resources>

    <!--
        Base application theme, dependent on API level. This theme is replaced
        by AppBaseTheme from res/values-vXX/styles.xml on newer devices.
    -->
    <style name="AppBaseTheme" parent="Theme.AppCompat.Light">
        <!--
            Theme customizations available in newer API levels can go in
            res/values-vXX/styles.xml, while customizations related to
            backward-compatibility can go here.
        -->
    </style>

    <!-- Application theme. -->
    <style name="AppTheme" parent="AppBaseTheme">
        <!-- All customizations that are NOT specific to a particular API-level can go here. -->
    </style>

</resources>
■AndroidManifest.xml

applicationのthemeでstyles.xmlの「AppBaseTheme」を指定します。
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.example.actionbar7"
    android:versionCode="1"
    android:versionName="1.0" >

    <uses-sdk
        android:minSdkVersion="8"
        android:targetSdkVersion="18" />

    <application
        android:allowBackup="true"
        android:icon="@drawable/ic_launcher"
        android:label="@string/app_name"
        android:theme="@style/AppBaseTheme" >
        <activity
            android:name="com.example.actionbar7.MainActivity"
            android:label="@string/app_name" >
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />

                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>
    </application>

</manifest>

■MainActivity.java

activityでは単純に表示だけを行います。
package com.example.actionbar7;

import android.os.Bundle;
import android.app.Activity;
import android.support.v7.app.ActionBar;
import android.support.v7.app.ActionBarActivity;
import android.view.Menu;

public class MainActivity extends ActionBarActivity {

 @Override
 protected void onCreate(Bundle savedInstanceState) {
  super.onCreate(savedInstanceState);
  setContentView(R.layout.activity_main);
  
  // action bar を取得する
  ActionBar ab = getSupportActionBar();
  
 }

 @Override
 public boolean onCreateOptionsMenu(Menu menu) {
  // Inflate the menu; this adds items to the action bar if it is present.
  getMenuInflater().inflate(R.menu.main, menu);
  return true;
 }

}

この記述で、2系では問題なくActionBarを使えるようになりますが、
これをAPI Level 16(Android 4.1.2)で実行してみると、
次のようなエラーが出てしまい落ちてしまいます(´;ω;`)ブワッ


Caused by: java.lang.IllegalStateException: You need to use a Theme.AppCompat theme (or descendant) with this activity.
エラー内容的に、Theme.AppCompaを使えって言われてると思いますが、
applicationのthemeでstyles.xmlで定義した「Theme.AppCompat.Light」を指定してるしな~と悩んでました。

そこでとりあえず、styles.xmlで定義されたものを使わずに、
次のように直接「Theme.AppCompat.Light」をthemeに指定してみると・・・o(゚Д゚ = ゚Д゚)o キョロキョロ
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.example.actionbar7"
    android:versionCode="1"
    android:versionName="1.0" >

    <uses-sdk
        android:minSdkVersion="8"
        android:targetSdkVersion="18" />

    <application
        android:allowBackup="true"
        android:icon="@drawable/ic_launcher"
        android:label="@string/app_name"
        android:theme="@style/Theme.AppCompat.Light" >
        <activity
            android:name="com.example.actionbar7.MainActivity"
            android:label="@string/app_name" >
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />

                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>
    </application>

</manifest>
起動キタ――(゚∀゚)――!!
念のため、エミュレーターのAndroid 3.0(API Level 11)でも確認しましたが問題なかったです( ´∀`)bグッ!

styles.xmlに定義されているものを利用するのはダメなのか・・・orz
そもそも、自分の認識がおかしいのか:(;゙゚'ω゚'):

何か他にもいろいろありそうな(゚∀゚)ヨカーン
その都度、つぶしていくしかないですね・・・orz


以上です(`・ω・´)ゞビシッ!!

参考URL

ActionBarを使ってみる(SearchViewを配置する Android 2.2以上)

Google Mapなどを利用していると上部に検索ボックスがあり、
そこに検索した結果の位置に地図が反映される機能が欲しい!!ということで、
さっそく試してみました(ΦωΦ)フフフ…

せっかくなのでActionBarの中に表示する方法でやりたいと思います。

やり方としては、SearchViewを使うパターンと、EditTexgを使うパターンがあるそうですが、
今回はSearchViewを使うパターンで試したいと思います。

SearchViewはAPI Levele 11(Android 3.0)以上から利用可能らしいです(´;ω;`)ウッ…
ただ、support libraryを使えば2.2系以上でも動作させる事も可能みたいです。

ActionBarにアクションアイテム(オプションメニューのアイコンなどのこと)の代わりに表示するビューやウィジェットの事を、
アクションビューと呼ぶそうです。

アクションアイテムにアクションビューを指定する場合には、2つの方法があります。
・android:actionLayout属性を使う(layoutのxmlを指定する)
・android:actionViewClass属性を使う(Viewを継承するクラスを指定する)
この2つを利用する場合には、android:showAsAction属性に「collapseActionView」を指定すると、
アクションアイテムをタップすると格納されている、アクションビューが表示されるようになる。

指定しなかった場合には、デフォルトでアクションビューがアクションアイテムに表示されます。

ハマった所といえば、
ActionBarに表示するメニューの定義XMLで
名前空間を指定しないといけない点です:(;゙゚'ω゚'):

API Level 11未満で利用したい場合には、
次の名前空間を記述して、それを利用しないとエラーになってしまいます(´;ω;`)ブワッ
<menu xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:myapp="http://schemas.android.com/apk/res-auto" >
SearchViewではサジェスト機能などもあるそうですが、
とりあえず今回はシンプルな構成でやりたいと思います( ´∀`)bグッ!

■AndroidManifest.xml
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.example.seachview1"
    android:versionCode="1"
    android:versionName="1.0" >

    <uses-sdk
        android:minSdkVersion="8"
        android:targetSdkVersion="18" />

    <application
        android:allowBackup="true"
        android:icon="@drawable/ic_launcher"
        android:label="@string/app_name"
        android:theme="@style/AppTheme" >
        <activity
            android:name="com.example.seachview1.MainActivity"
            android:label="@string/app_name" >
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />

                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>
    </application>

</manifest>
■res/values/strings.xml
<?xml version="1.0" encoding="utf-8"?>
<resources>
 
    <string name="app_name">SearchViewWithActionBarCompat</string>
    <string name="action_settings">Settings</string>
    <string name="hello_world">Hello world!</string>
    <string name="action_search">Search</string>
    <string name="search_hint">Search Places</string>
    <string name="search_label">Search Label</string>
    <string name="search_settings">Search Places</string>
 
</resources>
■res/values/styles.xml
<resources>

    <!--
        Base application theme, dependent on API level. This theme is replaced
        by AppBaseTheme from res/values-vXX/styles.xml on newer devices.
    -->
    <style name="AppBaseTheme" parent="Theme.AppCompat.Light">
        <!--
            Theme customizations available in newer API levels can go in
            res/values-vXX/styles.xml, while customizations related to
            backward-compatibility can go here.
        -->
    </style>

    <!-- Application theme. -->
    <style name="AppTheme" parent="AppBaseTheme">
        <!-- All customizations that are NOT specific to a particular API-level can go here. -->
    </style>

</resources>
■res/menu/main.xml

ActionBarに表示する、メニューの設定になります。

SearchViewはAPI Level 11から利用できるもので、
showAsAction 属性も API Level 11 から導入されたため、
それ以下のバージョンで利用する場合には、
名前空間として 「http://schemas.android.com/apk/res-auto」 を指定する必要があるそうです。

また、actionViewClassでsupport libraryのSearchViewを指定します。
※Viewを継承するクラスの完全修飾名を指定する。
actionViewClassでViewを指定した場合には、showAsActionに「collapseActionView」を利用する事も検討する。 これを設定すると、メニューをクリックした時にactionViewClassに設定したViewが表示される
設定されていない場合には、ActionBarの中に指定されたViewが表示された状態になる

showAsActionの条件が複数ある場合にはパイプでつなげる事。
always|collapseActionView

<menu xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:myapp="http://schemas.android.com/apk/res-auto" >

    <item
        android:id="@+id/action_search"
        android:orderInCategory="100"
        android:title="@string/action_search"
        myapp:actionViewClass="android.support.v7.widget.SearchView"
        myapp:showAsAction="always"/>
    <item
        android:id="@+id/action_settings"
        android:orderInCategory="100"
        myapp:showAsAction="ifRoom"
        android:title="@string/action_settings"/>

</menu>
■activity_main.xml

メインのレイアウトにはTextViewのみ配置します。
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:paddingBottom="@dimen/activity_vertical_margin"
    android:paddingLeft="@dimen/activity_horizontal_margin"
    android:paddingRight="@dimen/activity_horizontal_margin"
    android:paddingTop="@dimen/activity_vertical_margin"
    tools:context=".MainActivity" >

    <TextView
        android:id="@+id/text"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="@string/hello_world" />

</RelativeLayout>

■MainActivity.java

アクションビューを取得するには、onCreateOptionsMenuでgetActionViewを利用する。

今回は利用していませんが、android:showAsAction属性に「collapseActionView」を指定している状態で、
クラスに「CollapsibleActionView」を実装すると、
アクションビューが展開、または格納された時のコールバックメソッドをで通知を受けれるようになる。

package com.example.seachview1;

import android.support.v7.app.ActionBarActivity;
import android.support.v7.widget.SearchView;
import android.support.v7.widget.SearchView.OnCloseListener;
import android.support.v4.view.MenuItemCompat;
import android.text.TextUtils;
import android.util.Log;
import android.app.Activity;
import android.app.SearchManager;
import android.content.Context;
import android.content.Intent;
import android.os.Bundle;
import android.provider.SearchRecentSuggestions;
import android.view.Menu;
import android.view.MenuItem;
import android.view.MenuInflater;
import android.view.View;
import android.view.View.OnFocusChangeListener;
import android.widget.TextView;
import android.widget.Toast;

public class MainActivity extends ActionBarActivity {

 private static final String TAG = "MainActivity";
 private static TextView mTextView = null;

 // SearchVIewのリスナー
 private final SearchView.OnQueryTextListener mOnQueryTextListener = new SearchView.OnQueryTextListener() {
  /*
   * 文字に変更があったら(1文字ずつ呼ばれる)
   * 
   * @see android.support.v7.widget.SearchView.OnQueryTextListener#
   * onQueryTextChange(java.lang.String)
   */
  @Override
  public boolean onQueryTextChange(String newText) {

   Log.d(TAG, "onQueryTextChange "
     + (TextUtils.isEmpty(newText) ? "" : "Query so far: "
       + newText));

   return true;
  }

  /*
   * 文字入力を確定した場合
   * 
   * @see android.support.v7.widget.SearchView.OnQueryTextListener#
   * onQueryTextSubmit(java.lang.String)
   */
  @Override
  public boolean onQueryTextSubmit(String query) {

   Log.d(TAG, "onQueryTextSubmit Searching for: " + query);

   // 入力された文字を設定する
   mTextView.setText(query);

   return true;
  }
 };

 /** Called when the activity is first created. */
 @Override
 public void onCreate(Bundle savedInstanceState) {
  super.onCreate(savedInstanceState);
  setContentView(R.layout.activity_main);

  //
  mTextView = (TextView) findViewById(R.id.text);

 }

 /*
  * メニューの作成
  * 
  * @see android.app.Activity#onCreateOptionsMenu(android.view.Menu)
  */
 @Override
 public boolean onCreateOptionsMenu(Menu menu) {
  // Inflate the menu; this adds items to the action bar if it is present.
  getMenuInflater().inflate(R.menu.main, menu);

  // menu定義のitemのidがaction_searchのものを取得する
  MenuItem searchItem = menu.findItem(R.id.action_search);

  // SearchViewを取得する
  final SearchView searchView = (SearchView) MenuItemCompat
    .getActionView(searchItem);

  // 虫メガネのアイコンを表示するか
  searchView.setIconifiedByDefault(true);

  // Submitボタンを表示するか
  searchView.setSubmitButtonEnabled(false);

  // SearchViewに何も入力していない時のテキストを設定
  searchView.setQueryHint("検索文字を入力して下さい。");

  // リスナーを登録する
  searchView.setOnQueryTextListener(mOnQueryTextListener);

  return super.onCreateOptionsMenu(menu);
 }

}
実行結果は次のようになります。

 文字を入力すると、TextViewにもその結果が反映されます。


以上です(`・ω・´)ゞビシッ!!

参考URL