ページャーでフラグメントアクティビティがあります:
List<Fragment> fragments = new Vector<Fragment>();
fragments.add(Fragment.instantiate(this, PastEventListFragment.class.getName(),bundle));
fragments.add(Fragment.instantiate(this, EventListFragment.class.getName(),bundle));
this.mPagerAdapter = new EventPagerAdapter(super.getSupportFragmentManager(), fragments);
//
ViewPager pager = (ViewPager)super.findViewById(R.id.viewpager1);
pager.setAdapter(this.mPagerAdapter);
pager.setCurrentItem(1);
OnKeyDownイベントをキャッチします。
@Override
public boolean onKeyDown(int keyCode, KeyEvent event) {
if (keyCode == KeyEvent.KEYCODE_MENU) {
}
return super.onKeyDown(keyCode, event);
}
問題は、このアクティビティでインスタンス化したすべてのフラグメントでイベントを使用する方法です。ありがとう
できることは、フラグメントクラスでカスタムメソッドを定義することです。例えば:
public void myOnKeyDown(int key_code){
//do whatever you want here
}
activityクラスでキーダウンイベントが発生するたびにこのメソッドを呼び出します。例えば:
@Override
public boolean onKeyDown(int keyCode, KeyEvent event) {
if (keyCode == KeyEvent.KEYCODE_MENU) {
((PastEventListFragment)fragments.get(0)).myOnKeyDown(keyCode);
((EventListFragment)fragments.get(1)).myOnKeyDown(keyCode);
//and so on...
}
return super.onKeyDown(keyCode, event);
}
誰かがブロードキャストでそれを行う方法に興味を持っている場合:
OnViewCreatedのフラグメント内
@Override
public void onViewCreated(View view, Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
// Register to receive messages.
// We are registering an observer (mMessageReceiver) to receive Intents
// with actions named "custom-event-name".
LocalBroadcastManager.getInstance(this).registerReceiver(mMessageReceiver,
new IntentFilter("activity-says-hi"));
...}
// Our handler for received Intents. This will be called whenever an Intent
// with an action named "custom-event-name" is broadcasted.
private BroadcastReceiver mMessageReceiver = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
// Get extra data included in the Intent
doSomethingCauseVolumeKeyPressed();
}
};
あなたのキーイベント-アクティビティに入れるコード
@Override
public boolean dispatchKeyEvent(KeyEvent event) {
int action = event.getAction();
int keyCode = event.getKeyCode();
switch (keyCode) {
case KeyEvent.KEYCODE_VOLUME_UP:
if (action == KeyEvent.ACTION_DOWN) {
sendBroadcast();
}
return true;
case KeyEvent.KEYCODE_VOLUME_DOWN:
if (action == KeyEvent.ACTION_DOWN) {
sendBroadcast();
}
return true;
default:
return super.dispatchKeyEvent(event);
}
}
ブロードキャスト送信者:
private void sendVolumeBroadcast(){
Intent intent = new Intent("activity-says-hi");
LocalBroadcastManager.getInstance(this).sendBroadcast(intent);
}
他の人が述べたように、受け入れられた答えは、アクティビティとそのフラグメントの間の密結合をもたらします。
代わりに、何らかのイベントベースの実装を使用することをお勧めします。これははるかに再利用可能であり、より優れたソフトウェアアーキテクチャになります。以前のプロジェクトでは、次のいずれかのソリューションを使用しました(Kotlin):
AndroidのLocalBroadcastManagerの使用: ドキュメント
BroadcastReceiverを作成します。
class SomeBroadcastReceiver : BroadcastReceiver() {
override fun onReceive(context: Context?, intent: Intent?) {
val keyCode = intent?.getIntExtra("KEY_CODE", 0)
// Do something with the event
}
}
あなたの活動:
class SomeActivity : AppCompatActivity() {
override fun onKeyDown(keyCode: Int, event: KeyEvent?): Boolean {
val intent = Intent("SOME_TAG").apply { putExtra("KEY_CODE", keyCode) }
LocalBroadcastManager.getInstance(this).sendBroadcast(intent)
return super.onKeyDown(keyCode, event)
}
}
次に、フラグメント(またはサービスなど)のいずれかで:
class SomeFragment : Fragment() {
val receiver = SomeBroadcastReceiver()
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {
val filter = IntentFilter().apply { addAction("SOME_TAG") }
LocalBroadcastManager.getInstance(context!!).registerReceiver(receiver, filter)
return super.onCreateView(inflater, container, savedInstanceState)
}
}
EventBus を使用する
イベントクラスを作成します。
data class Event(val keyCode: Int)
あなたの活動:
class SomeActivity : AppCompatActivity() {
override fun onKeyDown(keyCode: Int, event: KeyEvent?): Boolean {
EventBus.getDefault().post(Event(keyCode))
return super.onKeyDown(keyCode, event)
}
}
次に、フラグメントで:
class SomeFragment : Fragment() {
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {
// Register for events
EventBus.getDefault().register(this)
return super.onCreateView(inflater, container, savedInstanceState)
}
@Subscribe
public fun onKeyEvent(event : Event) {
// Called by eventBus when an event occurs
}
override fun onDestroyView() {
super.onDestroyView()
EventBus.getDefault().unregister(this)
}
}
Android TVアプリ。
そして、この問題を次のように解決します。
OnCreateViewメソッドでは、Viewによって "requestFocus"を呼び出します。 (ViewAとしてマークします。)次に、KeyEventListenerをViewAに設定します。
あなたのケースでは、AdapterとPagerChangeListenerでそれを行う必要があります(set-KeyEventListener)。
ActivityとFragmentクラスをサブクラス化して、KeyEventsの受け渡しを実行しました。私にとっては、ローカルブロードキャストを送信するよりも明確に見えます。しかし、このソリューションはそれほど柔軟ではありません。好みの方法を自分で選択してください。
アクティビティは次のとおりです。
public abstract class KeyEventPassingActivity extends Activity {
public interface KeyEventListener extends View.OnKeyListener {
boolean isVisible();
View getView();
}
private final List<KeyEventListener> keyEventHandlerList = new ArrayList<>();
@Override
public boolean dispatchKeyEvent(KeyEvent event) {
for (KeyEventListener handler : keyEventHandlerList) {
if (handleKeyEvent(handler, event)) {
return true;
}
}
return super.dispatchKeyEvent(event);
}
void addKeyEventHandler(@NonNull KeyEventListener handler) {
keyEventHandlerList.add(handler);
}
void removeKeyEventHandler(@NonNull KeyEventListener handler) {
keyEventHandlerList.remove(handler);
}
/**
* @return <tt>true</tt> if the event was handled, <tt>false</tt> otherwise
*/
private boolean handleKeyEvent(@Nullable KeyEventListener listener, KeyEvent event) {
return listener != null
&& listener.isVisible()
&& listener.onKey(listener.getView(), event.getKeyCode(), event);
}
}
そしてフラグメント:
public abstract class KeyEventHandlingFragment extends Fragment
implements KeyEventPassingActivity.KeyEventListener {
@SuppressWarnings("deprecation")
@Override
public void onAttach(Activity activity) {
super.onAttach(activity);
if (activity instanceof KeyEventPassingActivity) {
((KeyEventPassingActivity) activity).addKeyEventHandler(this);
}
}
@Override
public void onDetach() {
Activity activity = getActivity();
if (activity instanceof KeyEventPassingActivity) {
((KeyEventPassingActivity) activity).removeKeyEventHandler(this);
}
super.onDetach();
}
}
要点: https://Gist.github.com/0neel/7d1ed5d26f2148b4168b6616337159ed
@ hsu.twの回答に続いて密結合を回避し、これを見つけました Gist 。
密結合の回避には代償が伴います:フォーカス可能なビューが必要です(幸いなことに、他のタッチイベントをリッスンするビューが前景にあるため、私の場合はそうでしたので、View.OnKeyListener
を追加しました)。
アクティビティとは無関係に、フラグメントのビューにView.OnKeyListener
を添付するために必要な手順は次のとおりです( Gist を確認してください)。
view.setFocusableInTouchMode(true);
view.requestFocus();
view.setOnKeyListener(pressKeyListener);
これをフラグメントのonViewCreated
コールバックに実装しました