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のタッチイベント(むしろこっちの方が多いかも)などでも使用する場面があると思うのでいろいろと応用がきくと思います。