Fragmentでのイベントハンドリング
FragmentにButtonを置いてみたけどレイアウトで定義したButtonのonClickがFragmentで実装できないじゃん!!とかいろいろな問題に直面したので頭を冷やして解決方法をメモします。
まず上記の例に関して言えば、そのFragmentを持つActivityで実装することができます。しかし、Fragmentが複数ある場合、FragmentそれぞれのボタンのイベントをActivityで実装しなければならず、Activityが煩雑化してしまいます。FragmentのイベントはFragmentで完結させたいですよね。と言うことで解決方法について説明します。
IDでボタンのインスタンスを取得して、リスナーを登録する
これは超簡単!
まずレイアウトで定義したウィジェットのIDからオブジェクトを取得します。
その後、リスナーを登録してあげれば完成です。
@Override public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { View view = (View)inflater.inflate(R.layout.fragment_main, container, false); //IDからオブジェクトを取得 Button button = (Button)view.findViewById(R.id.button); //リスナーを登録 button.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { Log.v("button:", "clicked!"); } }); return view; }
これでButtonをタップするとログにメッセージが表示されると思います。
アクティビティへのイベントコールバックを作成する
こちらは公式サイトのAPIガイドにある方法なのですが、Activityの何かしらの情報の取得やUIの操作をするのであれば以下のように実装しましょう。
まずはFragmentにInterfaceを定義しましょう。
public class MainFragment extends Fragment { //Activityにイベントを通知する役割を持つ public interface OnClickListener { void onClick(); } @Override public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { return inflater.inflate(R.layout.fragment_main, container, false); } }
このOnClickListenerをActivityのインターフェースにしてonClickを実装します。
public class MainActivity extends AppCompatActivity implements MainFragment.OnClickListener { @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); } @Override public void onClick() { Log.v("onClick:", "想いよ届け"); } }
その後、Fragmentに戻ってOnClickListenerの変数をフィールド持ち、Fragmentのライフサイクルの一つであるonAttach()を以下のように実装します。
public class MainFragment extends Fragment { OnClickListener _clickListener; public interface OnClickListener { void onClick(); } @Override public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { return inflater.inflate(R.layout.fragment_main, container, false); } @Override public void onAttach(Context context) { super.onAttach(context); try { _clickListener = (OnClickListener) context; } catch (ClassCastException e) { throw new ClassCastException(getActivity().toString() + "must implement OnArticleSelectedListener."); } } }
ちなみにonAttach()はFragmentをActivityに追加する際に呼ばれるメソッドです。メモメモ、、。
onAttach()内ではActivityがOnClickListenerを実装しているかをハンドリングし、成功すればそれをフィールドに持つようにしています。これで先ほどのIDでオブジェクトを取得する方法と合わせて、
//リスナーを登録 button.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { _clickListener.onClick(); } });
これでFragmentのButtonを押した際のイベントがActivityに通知されるようになります。
この方法、Buttonに限らずListViewのタッチイベント(むしろこっちの方が多いかも)などでも使用する場面があると思うのでいろいろと応用がきくと思います。
Fragmentを表示する方法
Fragmentを利用する場合API level > 11が必要
手順
- fragmentのレイアウト作成
- Fragmentのサブクラス作成
- Activityのレイアウトにて紐付け
詳細
fragmentのレイアウト作成します。res->layoutでレイアウト(ここではfargment_main.xml)を作成して以下を記述。
<?xml version="1.0" encoding="utf-8"?> <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="match_parent"> <!--表示確認用のテキスト--> <TextView android:text="fragment" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_centerInParent="true"/> </RelativeLayout>
続いてFragmentのサブクラス(ここではMainFragment)を作成して以下を記述しましょう。
public class MainFragment extends Fragment { @Override public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { return inflater.inflate(R.layout.fragment_main, container, false); } }
最後にActivityに紐付いているxml(ここではactivity_main.xml)で以下を記述して完成です。
<fragment android:name="com.sfs.crypton.myapplication.MainFragment" android:id="@+id/mainFragment" android:layout_width="match_parent" android:layout_height="match_parent"/>
Androidでシンプルなリストを表示する
まずは表示するActivityのxmlにListViewを定義しましょう。
res->layoutにあるxmlファイルにて以下を記述します。
<ListView android:id="@+id/listView" android:layout_width="match_parent" android:layout_height="match_parent"/>
続いてそのActivityのクラス内のonCreateメソッドにて以下のように記述します。
@Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); //xmlで定義したListViewを紐付ける ListView listView = (ListView)findViewById(R.id.listView); //adapterを生成して、ListViewにセットする ArrayAdapter<String> arrayAdapter = new ArrayAdapter<String>(this, android.R.layout.simple_list_item_1); arrayAdapter.add("list1"); arrayAdapter.add("list2"); arrayAdapter.add("list3"); if(listView != null) listView.setAdapter(arrayAdapter); }
以上でひとまずは、リストが表示されるかと思います。
ここからカスタムレイアウトを作成したり、いろいろな応用すると勉強になるかと思います。
Adapterについてじっくり学習することがミソです。
アプリ開発にあたっての学習資料
- The Swift Programing Language(Swift 2.2)
- The Swift Programing Language(Swift 3 Beta)
- Using Swift with Cocoa and Objective-C(Swift 2.2)
- Using Swift with Cocoa and Objective-C(Swift 3 Beta)
Androidのコンポーネントについて
アクティビティ
アクティビティは1つのUIで1つの画面を表す。
サービス
長時間の操作やリモートプロセスを処理するためのバックグラウンドで実行するコンポーネント。
コンテンツプロバイダ
共有されているアプリデータの管理。データはファイルシステム、システム、SQLiteデータベース、ウェブ、アプリがアクセスできるあらゆる永続性のストレージに保存できる。
コンテンツプロバイダを介して、他のアプリがデータをクエリしたり、修正したりすることもできる。
ブロードキャストレシーバー
ブロードキャストレシーバーは共有されているアプリデータを管理する。データは、ファイル、システム、SQLiteデータベース、ウェブ、アプリがアクセスできる、あらゆる永続性のストレージに保存できる。コンテンツプロバイダを介して、他のアプリがデータをクエリしたり、修正することもできる。例えばAndroidシステムではユーザーの連絡先情報を管理するコンテンツプロバイダーの一部(ContactsContract.Dataなど)に問い合わせて、特定の人物に関する情報を読み取ったり書き込んだりできる。