Android Fragmentで、Android Activityでの実装と同様に、onBackPressed()
を実装する方法はありますか?
フラグメントのライフサイクルには「onBackPressed()」がありません。Android 3.0 のフラグメントで onBackPressed()
をオーバーライドする他の代替方法はありますか?
このようにして、アクティビティの「onBackPressed」をオーバーライドしました。 すべての「フラグメントトランザクション」は、コミット前の「addToBackStack」です。
@Override
public void onBackPressed() {
int count = getSupportFragmentManager().getBackStackEntryCount();
if (count == 0) {
super.onBackPressed();
//additional code
} else {
getSupportFragmentManager().popBackStack();
}
}
私は最善の解決策です。
シンプルなインターフェイスを作成:
public interface IOnBackPressed {
/**
* If you return true the back press will not be taken into account, otherwise the activity will act naturally
* @return true if your processing has priority if not false
*/
boolean onBackPressed();
}
そしてあなたの活動で。
public class MyActivity extends Activity {
@Override public void onBackPressed() {
Fragment fragment = getSupportFragmentManager().findFragmentById(R.id.main_container);
if (!(fragment instanceof IOnBackPressed) || !((IOnBackPressed) fragment).onBackPressed()) {
super.onBackPressed();
}
} ...
}
最後にあなたのフラグメントで:
public class MyFragment extends Fragment implements IOnBackPressed{
@Override
public boolean onBackPressed() {
if (myCondition) {
//action not popBackStack
return true;
} else {
return false;
}
}
}
interface IOnBackPressed {
fun onBackPressed(): Boolean
}
class MyActivity : AppCompatActivity() {
override fun onBackPressed() {
val fragment =
this.supportFragmentManager.findFragmentById(R.id.main_container)
(fragment as? IOnBackPressed)?.onBackPressed()?.not()?.let {
super.onBackPressed()
}
}
}
class MyFragment : Fragment(), IOnBackPressed {
override fun onBackPressed(): Boolean {
return if (myCondition) {
//action not popBackStack
true
} else {
false
}
}
}
HaMMeRedの回答によると、どのように動作するかの疑似コードは以下の通りです。
あなたのメインアクティビティがBaseActivity
と呼ばれ、子フラグメント(SlidingMenuリブの例のように)を持っているとします。
以下はその手順です。
まず、インターフェイスを作成し、そのインターフェイスを実装したクラスでジェネリックメソッドを持つ必要があります。
1.クラスインターフェイス OnBackPressedListener
を作成する。
public interface OnBackPressedListener {.
public void doBack();
}
2.OnBackPressedListener` のスキルを実装したクラスを作成する。
public class BaseBackPressedListener implements OnBackPressedListener {.
private final FragmentActivity activity;
public BaseBackPressedListener(FragmentActivity activity) {。
this.activity = activityです。
}
オーバーライド
public void doBack() {
activity.getSupportFragmentManager().popBackStack(null, FragmentManager.POP_BACK_STACK_INCLUSIVE);
}
}
3.これからは、コード BaseActivity
とその断片に取り組みます。
4.クラス BaseActivity
の上にプライベートリスナーを作成する。
protected OnBackPressedListener onBackPressedListener;
BaseActivity
にリスナーを設定するメソッドを作成する。
public void setOnBackPressedListener(OnBackPressedListener onBackPressedListener) {。
this.onBackPressedListener = onBackPressedListener;
}
オーバーライド onBackPressed
で、そのようなものを実装する。
オーバーライド
public void onBackPressed() {。
if (onBackPressedListener != null)
onBackPressedListener.doBack()を実行する。
さもなくば
super.onBackPressed()です。
あなたのフラグメントの onCreateView
で、私たちのリスナーを追加します。
オーバーライド
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {.
activity = getActivity();
((BaseActivity)activity).setOnBackPressedListener(new BaseBackPressedListener(activity));
ビュービュー = ... ;
//ビューを使用する
ビューを返します。
}
これで、フラグメントで戻るをクリックしたときに、カスタムオンバックメソッドをキャッチできるようになりました。
これは私のために働いた:https://stackoverflow.com/a/27145007/3934111。
@Override
public void onResume() {
super.onResume();
if(getView() == null){
return;
}
getView().setFocusableInTouchMode(true);
getView().requestFocus();
getView().setOnKeyListener(new View.OnKeyListener() {
@Override
public boolean onKey(View v, int keyCode, KeyEvent event) {
if (event.getAction() == KeyEvent.ACTION_UP && keyCode == KeyEvent.KEYCODE_BACK){
// handle back button's click listener
return true;
}
return false;
}
});
}
もしそのような機能が必要であれば、アクティビティでそれをオーバーライドし、すべてのフラグメントに YourBackPressed
インターフェースを追加し、戻るボタンが押されたときに関連するフラグメントでそれを呼び出す必要があります。
編集部:前回の回答を追記させていただきます。
もし、今日これを行うのであれば、ブロードキャスト、あるいは、他のパネルがマスター/メインコンテンツパネルと一体となって更新されることを期待するならば、順序付きブロードキャストを使用することになるでしょう。
サポートライブラリの LocalBroadcastManager
を使えば、onBackPressed
でブロードキャストを送信し、気になるフラグメントでサブスクライブするだけでいい。Messagingの方がより分離された実装で、よりスケールすると思うので、今はそちらを公式に推奨しています。新しく作成した ACTION_BACK_PRESSED
をアクティビティから送信し、関連するフラグメントでそれをリッスンします。
この質問と回答の一部は5年以上前のものなので、私の解決策を共有しましょう。 これは、@ oyenigunからの回答のフォローアップと近代化です。
更新:。 この記事の下部に、アクティビティをまったく含まない抽象フラグメント拡張を使用した代替実装を追加しました。これは、異なるバック動作を必要とするネストされたフラグメントを含む、より複雑なフラグメント階層を持つ人にとって役立ちます。
私が使用するフラグメントの一部は、バックボタンで却下したい小さなビューを持っているため、これを実装する必要がありました。, ポップアップする小さな情報ビューなど。, 等, ただし、これはフラグメント内のバックボタンの動作をオーバーライドする必要がある人には適しています。
まず、インターフェイスを定義します。
public interface Backable {
boolean onBackPressed();
}
このインターフェイスは、 Backable
(私は規則に名前を付けるためのステッカーです)と呼ばれ、 boolean
値を返す必要がある単一のメソッド onBackPressed()
があります。 バックボタンプレスがバックイベントを「吸収」したかどうかを知る必要があるため、ブール値を適用する必要があります。 「true」を返すことは、それが存在し、それ以上のアクションは必要ないことを意味します。それ以外の場合、「false」は、デフォルトのバックアクションをまだ実行する必要があることを示しています。 このインターフェースは独自のファイルである必要があります(できれば「インターフェース」という名前の別のパッケージで)。 クラスをパッケージに分離することは良い習慣です。
2番目に、上部のフラグメントを見つけます。
バックスタックで最後の「フラグメント」オブジェクトを返すメソッドを作成しました。 タグを使用します。.. IDを使用する場合は、必要な変更を加えてください。 ナビゲーション状態などを扱うユーティリティクラスにこの静的メソッドがあります。.. もちろん、あなたにぴったりの場所に置いてください。 啓発のために、私は「NavUtils」と呼ばれるクラスに私を入れました。
public static Fragment getCurrentFragment(Activity activity) {
FragmentManager fragmentManager = activity.getFragmentManager();
if (fragmentManager.getBackStackEntryCount() > 0) {
String lastFragmentName = fragmentManager.getBackStackEntryAt(
fragmentManager.getBackStackEntryCount() - 1).getName();
return fragmentManager.findFragmentByTag(lastFragmentName);
}
return null;
}
バックスタック数が0より大きいことを確認してください。そうでない場合、実行時に「ArrayOutOfBoundsException」がスローされる可能性があります。 0以下の場合はnullを返します。 後でnull値を確認します。..
3番目、フラグメントに実装。
バックボタンの動作をオーバーライドする必要があるフラグメントに「Backable」インターフェイスを実装します。 実装方法を追加します。
public class SomeFragment extends Fragment implements
FragmentManager.OnBackStackChangedListener, Backable {
...
@Override
public boolean onBackPressed() {
// Logic here...
if (backButtonShouldNotGoBack) {
whateverMethodYouNeed();
return true;
}
return false;
}
}
onBackPressed()
オーバーライドに、必要なロジックを配置します。 バックボタンを not にしたい場合は、バックスタック(デフォルトの動作)をポップし、 true を返します。これは、バックイベントが吸収されたことです。 それ以外の場合は、falseを返します。
最後に、あなたの活動で。..。
onBackPressed()
メソッドをオーバーライドし、このロジックを追加します。
@Override
public void onBackPressed() {
// Get the current fragment using the method from the second step above...
Fragment currentFragment = NavUtils.getCurrentFragment(this);
// Determine whether or not this fragment implements Backable
// Do a null check just to be safe
if (currentFragment != null && currentFragment instanceof Backable) {
if (((Backable) currentFragment).onBackPressed()) {
// If the onBackPressed override in your fragment
// did absorb the back event (returned true), return
return;
} else {
// Otherwise, call the super method for the default behavior
super.onBackPressed();
}
}
// Any other logic needed...
// call super method to be sure the back button does its thing...
super.onBackPressed();
}
バックスタックに現在のフラグメントが表示され、nullチェックを実行して、「Backable」インターフェイスを実装しているかどうかを判断します。 吸収された場合は、イベントが吸収されたかどうかを判断します。 その場合、「onBackPressed()」で完了し、戻ることができます。 それ以外の場合は、通常のバックプレスとして扱い、スーパーメソッドを呼び出します。
アクティビティを含まない2番目のオプション。
アクティビティがこれをまったく処理したくない場合があり、フラグメント内で直接処理する必要があります。 しかし、バックプレスAPIを備えたフラグメントを使用することはできません? フラグメントを新しいクラスに拡張するだけです。
フラグメントを拡張し、「View.OnKeyListner」インターフェイスを実装する抽象クラスを作成します。..
import android.app.Fragment;
import android.os.Bundle;
import android.view.KeyEvent;
import android.view.View;
public abstract class BackableFragment extends Fragment implements View.OnKeyListener {
@Override
public void onViewCreated(View view, Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
view.setFocusableInTouchMode(true);
view.requestFocus();
view.setOnKeyListener(this);
}
@Override
public boolean onKey(View v, int keyCode, KeyEvent event) {
if (event.getAction() == KeyEvent.ACTION_UP) {
if (keyCode == KeyEvent.KEYCODE_BACK) {
onBackButtonPressed();
return true;
}
}
return false;
}
public abstract void onBackButtonPressed();
}
ご覧のとおり、「BackableFragment」を拡張するフラグメントは、「View.OnKeyListener」インターフェイスを使用して自動的にバッククリックをキャプチャします。 標準ロジックを使用して実装された「onKey()」メソッド内から抽象的な「onBackButtonPressed()」メソッドを呼び出して、バックボタンを押すのを識別します。 バックボタン以外のキークリックを登録する必要がある場合は、フラグメントの「onKey()」をオーバーライドするときに必ず「スーパー」メソッドを呼び出してください。そうしないと、抽象化の動作が_オーバーライドされます。
使いやすく、拡張して実装するだけです。
public class FragmentChannels extends BackableFragment {
...
@Override
public void onBackButtonPressed() {
if (doTheThingRequiringBackButtonOverride) {
// do the thing
} else {
getActivity().onBackPressed();
}
}
...
}
スーパークラスの「onBackButtonPressed()」メソッドは抽象的であるため、拡張したら「onBackButtonPressed()」を実装する必要があります。 フラグメントクラス内でアクションを実行するだけで、プレスの吸収をアクティビティにリレーする必要がないため、「void」を返します。 確認してくださいバックボタンで行っていることを処理する必要がない場合は、アクティビティを「onBackPressed()」メソッドと呼びます。そうしないと、バックボタンが無効になります。.. そしてあなたはそれを望んでいません。!
警告。 ご覧のとおり、これによりキーリスナーがフラグメントのルートビューに設定されます。これに焦点を当てる必要があります。 このクラスを拡張するフラグメント(または同じ他の内部フラグメントまたはビュー)に含まれる編集テキスト(またはその他のフォーカス盗むビュー)がある場合は、個別に処理する必要があります。 EditTextを拡張に、バックプレスに集中できないようにするための良い記事があります。
誰かがこれを役立ててくれることを願っています。 幸せなコーディング。
解決策は簡単です。
1)すべてのフラグメントが拡張するベースフラグメントクラスがある場合は、このコードをクラスに追加し、それ以外の場合はそのようなベースフラグメントクラスを作成します。
/*
* called when on back pressed to the current fragment that is returned
*/
public void onBackPressed()
{
// add code in super class when override
}
2)アクティビティクラスで、次のようにbackPressedをオーバーライドします。
private BaseFragment _currentFragment;
@Override
public void onBackPressed()
{
super.onBackPressed();
_currentFragment.onBackPressed();
}
3)フラグメントクラスで、目的のコードを追加します。
@Override
public void onBackPressed()
{
setUpTitle();
}
onBackPressed()
により、フラグメントがアクティビティから切り離されます。
@Sterling Diazの回答によると、彼は正しいと思います。 しかし、いくつかの状況は間違っています。 (例. 画面を回転)。
ですから、目標を達成するかどうかを検出できると思います。
onDetach()
またはonDestroyView()
で記述できます。 それは仕事です。
@Override
public void onDetach() {
super.onDetach();
if(isRemoving()){
// onBackPressed()
}
}
@Override
public void onDestroyView() {
super.onDestroyView();
if(isRemoving()){
// onBackPressed()
}
}
以下のようにプロジェクトにインターフェイスを追加する必要があります。
public interface OnBackPressed {
void onBackPressed();
}
そして、このインターフェイスをフラグメントに実装する必要があります。
public class SampleFragment extends Fragment implements OnBackPressed {
@Override
public void onBackPressed() {
//on Back Pressed
}
}
そして、以下のようなBackPressedイベントでのアクティビティの下で、このonBackPressedイベントをトリガーできます。
public class MainActivity extends AppCompatActivity {
@Override
public void onBackPressed() {
Fragment currentFragment = getSupportFragmentManager().getFragments().get(getSupportFragmentManager().getBackStackEntryCount() - 1);
if (currentFragment instanceof OnBackPressed) {
((OnBackPressed) currentFragment).onBackPressed();
}
super.onBackPressed();
}
}
まあ私はこのようにそれをやった、そしてそれは私のために働く。
シンプルなインターフェース。
FragmentOnBackClickInterface.java 。
public interface FragmentOnBackClickInterface {
void onClick();
}
実装の例。
MyFragment.java 。
public class MyFragment extends Fragment implements FragmentOnBackClickInterface {
// other stuff
public void onClick() {
// what you want to call onBackPressed?
}
次に、アクティビティでbackPressedをオーバーライドします。
@Override
public void onBackPressed() {
int count = getSupportFragmentManager().getBackStackEntryCount();
List<Fragment> frags = getSupportFragmentManager().getFragments();
Fragment lastFrag = getLastNotNull(frags);
//nothing else in back stack || nothing in back stack is instance of our interface
if (count == 0 || !(lastFrag instanceof FragmentOnBackClickInterface)) {
super.onBackPressed();
} else {
((FragmentOnBackClickInterface) lastFrag).onClick();
}
}
private Fragment getLastNotNull(List<Fragment> list){
for (int i= list.size()-1;i>=0;i--){
Fragment frag = list.get(i);
if (frag != null){
return frag;
}
}
return null;
}
EventBusを使用する場合、それはおそらくはるかに単純なソリューションです。
あなたのフラグメントで:
@Override
public void onAttach(Activity activity) {
super.onAttach(activity);
EventBus.getDefault().register(this);
}
@Override
public void onDetach() {
super.onDetach();
EventBus.getDefault().unregister(this);
}
// This method will be called when a MessageEvent is posted
public void onEvent(BackPressedMessage type){
getSupportFragmentManager().popBackStack();
}
アクティビティクラスでは、以下を定義できます。
@Override
public void onStart() {
super.onStart();
EventBus.getDefault().register(this);
}
@Override
public void onStop() {
EventBus.getDefault().unregister(this);
super.onStop();
}
// This method will be called when a MessageEvent is posted
public void onEvent(BackPressedMessage type){
super.onBackPressed();
}
@Override
public void onBackPressed() {
EventBus.getDefault().post(new BackPressedMessage(true));
}
BackPressedMessage.javaは単なるPOJOオブジェクトです。
これは非常にクリーンで、インターフェース/実装の面倒はありません。
これが私の解決策です。
MyActivity.java:。
public interface OnBackClickListener {
boolean onBackClick();
}
private OnBackClickListener onBackClickListener;
public void setOnBackClickListener(OnBackClickListener onBackClickListener) {
this.onBackClickListener = onBackClickListener;
}
@Override
public void onBackPressed() {
if (onBackClickListener != null && onBackClickListener.onBackClick()) {
return;
}
super.onBackPressed();
}
フラグメント:。
((MyActivity) getActivity()).setOnBackClickListener(new MyActivity.OnBackClickListener() {
@Override
public boolean onBackClick() {
if (condition) {
return false;
}
// some codes
return true;
}
});
public class MyActivity extends Activity {
protected OnBackPressedListener onBackPressedListener;
public interface OnBackPressedListener {
void doBack();
}
public void setOnBackPressedListener(OnBackPressedListener onBackPressedListener) {
this.onBackPressedListener = onBackPressedListener;
}
@Override
public void onBackPressed() {
if (onBackPressedListener != null)
onBackPressedListener.doBack();
else
super.onBackPressed();
}
@Override
protected void onDestroy() {
onBackPressedListener = null;
super.onDestroy();
}
}
フラグメントに以下を追加します。mainactivityのインターフェイスを実装することを忘れないでください。
public class MyFragment extends Framgent implements MyActivity.OnBackPressedListener {
@Override
public void onViewCreated(View view, Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
((MyActivity) getActivity()).setOnBackPressedListener(this);
}
@Override
public void doBack() {
//BackPressed in activity will call this;
}
}
@Override
public void onResume() {
super.onResume();
getView().setFocusableInTouchMode(true);
getView().requestFocus();
getView().setOnKeyListener(new View.OnKeyListener() {
@Override
public boolean onKey(View v, int keyCode, KeyEvent event) {
if (event.getAction() == KeyEvent.ACTION_UP && keyCode == KeyEvent.KEYCODE_BACK) {
// handle back button
replaceFragmentToBackStack(getActivity(), WelcomeFragment.newInstance(bundle), tags);
return true;
}
return false;
}
});
}
非常に短くて甘い答え:
getActivity().onBackPressed();
私のケースのシナリオ全体の説明:
MainActivityにFragmentAがあります。 FragmentAからFragmentBを開きます(FragmentBは子またはネストされたFragmentAのフラグメントです)。
Fragment duedateFrag = new FragmentB();
FragmentTransaction ft = getFragmentManager().beginTransaction();
ft.replace(R.id.container_body, duedateFrag);
ft.addToBackStack(null);
ft.commit();
FragmentBからFragmentAに移動する場合は、FragmentBに getActivity().onBackPressed();
と入力するだけです。
次の手順に従ってください:。
常にフラグメントを追加しながら。
fragmentTransaction.add(R.id.fragment_container, detail_fragment, "Fragment_tag").addToBackStack(null).commit();
次に、メインアクティビティで「onBackPressed()」をオーバーライドします。
if (getSupportFragmentManager().getBackStackEntryCount() > 0) {
getSupportFragmentManager().popBackStack();
} else {
finish();
}
アプリのバックボタンを処理するには、
Fragment f = getActivity().getSupportFragmentManager().findFragmentByTag("Fragment_tag");
if (f instanceof FragmentName) {
if (f != null)
getActivity().getSupportFragmentManager().beginTransaction().remove(f).commit()
}
それでおしまい。!