onBackPressed()
Androidアクティビティで実装する方法と同様に、Androidフラグメントで実装できる方法はありますか?
フラグメントのライフサイクルにはありませんonBackPressed()
。onBackPressed()
Android 3.0フラグメントを乗り越える他の方法はありますか?
onBackPressed()
Androidアクティビティで実装する方法と同様に、Androidフラグメントで実装できる方法はありますか?
フラグメントのライフサイクルにはありませんonBackPressed()
。onBackPressed()
Android 3.0フラグメントを乗り越える他の方法はありますか?
回答:
このようにonBackPressed
して、アクティビティでオーバーライドを解決しました。すべてのFragmentTransaction
です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
}
}
}
R.id.main_container
?それはFragmentPagerのIDですか?
.?
)と非nullの強制()を混在させると!!
、NPEが発生する可能性があります。キャストが常に安全であるとは限りません。私はむしろ書きたいif ((fragment as? IOnBackPressed)?.onBackPressed()?.not() == true) { ... }
kotlineyを以上(fragment as? IOnBackPressed)?.onBackPressed()?.not()?.let { ... }
.onBackPressed()?.takeIf { !it }?.let{...}
?.not()
逆を返すだけです。
val fragment = this.supportFragmentManager.findFragmentById(R.id.flContainer) as? NavHostFragment val currentFragment = fragment?.childFragmentManager?.fragments?.get(0) as? IOnBackPressed currentFragment?.onBackPressed()?.takeIf { !it }?.let{ super.onBackPressed() }
これは、KotlinとNavigationControllerを使用するユーザー向けです
@HaMMeRedの回答によると、これはどのように機能するかを示す疑似コードです。BaseActivity
(SlidingMenu libの例のように)子フラグメントを持つメインアクティビティが呼び出されたとしましょう。手順は次のとおりです。
最初に、ジェネリックメソッドを持つインターフェースを実装するインターフェースとクラスを作成する必要があります。
クラスインターフェイスの作成 OnBackPressedListener
public interface OnBackPressedListener {
public void doBack();
}
スキルを実装するクラスを作成する OnBackPressedListener
public class BaseBackPressedListener implements OnBackPressedListener {
private final FragmentActivity activity;
public BaseBackPressedListener(FragmentActivity activity) {
this.activity = activity;
}
@Override
public void doBack() {
activity.getSupportFragmentManager().popBackStack(null, FragmentManager.POP_BACK_STACK_INCLUSIVE);
}
}
今から、コードBaseActivity
とそのフラグメントに取り組みます
クラスの上にプライベートリスナーを作成する BaseActivity
protected OnBackPressedListener onBackPressedListener;
リスナーを設定するcreateメソッド BaseActivity
public void setOnBackPressedListener(OnBackPressedListener onBackPressedListener) {
this.onBackPressedListener = onBackPressedListener;
}
オーバーライドでonBackPressed
そのようなものを実装する
@Override
public void onBackPressed() {
if (onBackPressedListener != null)
onBackPressedListener.doBack();
else
super.onBackPressed();
あなたのフラグメントにonCreateView
あなたは私たちのリスナーを追加する必要があります
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
activity = getActivity();
((BaseActivity)activity).setOnBackPressedListener(new BaseBackPressedListener(activity));
View view = ... ;
//stuff with view
return view;
}
ほら、今度はフラグメントをクリックして戻ると、カスタムのon backメソッドをキャッチする必要があります。
onBackPressed()
場合、「戻る」ボタンが押されたときにどのフラグメントが表示されていたかをどのように判断しますか?
((BaseActivity)activity).setOnBackPressedListener(new OnBackpressedListener(){ public void doBack() { //...your stuff here }});
これは私のために働きました: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
Support Libraryでこれを支援できますonBackPressed
。気になるフラグメントをブロードキャストで送信してサブスクライブするだけです。メッセージングはより分離された実装であり、拡張性が高いと思うので、これが私の公式の実装推奨事項になります。Intent
のアクションをメッセージのフィルターとして使用するだけです。新しく作成したACTION_BACK_PRESSED
を送信し、アクティビティから送信して、関連するフラグメントでリッスンします。
LocalBroadcastManager
注文した放送を行うことはできません
どれも簡単に実装できず、最適な方法で機能しません。
フラグメントには、仕事をするonDetachメソッド呼び出しがあります。
@Override
public void onDetach() {
super.onDetach();
PUT YOUR CODE HERE
}
これは仕事をします。
androidx.appcompat:appcompat:1.1.0
以上を使用している場合はOnBackPressedCallback
、次のようにフラグメントにを追加できます
requireActivity()
.onBackPressedDispatcher
.addCallback(this, object : OnBackPressedCallback(true) {
override fun handleOnBackPressed() {
Log.d(TAG, "Fragment back pressed invoked")
// Do custom work here
// if you want onBackPressed() to be called as normal afterwards
if (isEnabled) {
isEnabled = false
requireActivity().onBackPressed()
}
}
}
)
https://developer.android.com/guide/navigation/navigation-custom-backを参照してください
androidx-core-ktx
、使用できますrequireActivity().onBackPressedDispatcher.addCallback(viewLifecycleOwner) { /* code to be executed when back is pressed */ }
LifecycleOwner
この例のようにparamを追加する必要があることに注意することが重要です。これがないと、handleBackPressed()
[戻る]ボタンが押された場合、後で開始されたフラグメントが呼び出されます。
addToBackStack
以下のようにフラグメント間を移行しているときに追加してください:
fragmentManager.beginTransaction().replace(R.id.content_frame,fragment).addToBackStack("tag").commit();
を書くとaddToBackStack(null)
、それだけで処理しますが、タグを付けると、手動で処理する必要があります。
この質問といくつかの回答は5年以上前のものなので、私の解決策を共有しましょう。これは、@ oyenigunからの回答に対するフォローアップと最新化です。
更新: この記事の最後で、アクティビティをまったく含まない抽象Fragment拡張を使用した代替実装を追加しました。これは、さまざまなバック動作を必要とするネストされたフラグメントを含むより複雑なフラグメント階層を持つ人にとって便利です。
私が使用するフラグメントの一部は、ポップアップボタンなどの小さな情報ビューなど、戻るボタンで閉じたい小さなビューを持っているため、これを実装する必要がありましたが、これは、フラグメント内の戻るボタン。
まず、インターフェースを定義します
public interface Backable {
boolean onBackPressed();
}
私が呼び出すこのインターフェースBackable
(私は命名規則のスティックラーです)にはonBackPressed()
、boolean
値を返す必要のある単一のメソッドがあります。戻るボタンの押下が戻るイベントを「吸収」したかどうかを知る必要があるため、ブール値を適用する必要があります。戻るtrue
ということは、それがあり、それ以上のアクションは必要ないことを意味しfalse
ます。このインターフェースは、それ自体のファイルである必要があります(できれば、interfaces
)。クラスをパッケージに分離することをお勧めします。
次に、上のフラグメントを見つけます
Fragment
バックスタックの最後のオブジェクトを返すメソッドを作成しました。タグを使用しています... 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値を確認します...
第三に、断片的に実装する
Backable
戻るボタンの動作をオーバーライドする必要があるフラグメントにインターフェイスを実装します。実装方法を追加します。
public class SomeFragment extends Fragment implements
FragmentManager.OnBackStackChangedListener, Backable {
...
@Override
public boolean onBackPressed() {
// Logic here...
if (backButtonShouldNotGoBack) {
whateverMethodYouNeed();
return true;
}
return false;
}
}
ではonBackPressed()
、オーバーライド、何が必要ロジック置きます。戻るボタンで戻るスタックをポップしない場合(デフォルトの動作)、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()
あり、戻ることができます。それ以外の場合は、通常のバックプレスとして扱い、superメソッドを呼び出します。
アクティビティを含まない2番目のオプション
場合によっては、アクティビティでこれをまったく処理したくなく、フラグメント内で直接処理する必要があります。しかし、あなたはできないと誰が言う、バックプレスAPIを使用してフラグメントを作成するか?フラグメントを新しいクラスに拡張するだけです。
Fragmentを拡張し、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
インターフェースを使用して自動的にバッククリックをキャプチャします。標準ロジックを使用してonBackButtonPressed()
実装されたonKey()
メソッド内から抽象メソッドを呼び出し、戻るボタンの押下を識別します。戻るボタン以外のキークリックを登録する必要がある場合は、フラグメントでsuper
オーバーライドするときに必ずメソッドを呼び出してonKey()
ください。そうしないと、オーバーライドされます、抽象化で動作を。
使いやすく、拡張して実装するだけです。
public class FragmentChannels extends BackableFragment {
...
@Override
public void onBackButtonPressed() {
if (doTheThingRequiringBackButtonOverride) {
// do the thing
} else {
getActivity().onBackPressed();
}
}
...
}
onBackButtonPressed()
スーパークラスのメソッドは抽象なので、拡張したら実装する必要がありますonBackButtonPressed()
。void
フラグメントクラス内でアクションを実行する必要があるだけで戻り、プレスの吸収をアクティビティに中継する必要がないため、戻ります。戻るボタンを使用して行う処理で処理が不要な場合は、必ず Activity onBackPressed()
メソッドを呼び出してください。そうしないと、戻るボタンが無効になります。これは望ましくありません。
警告 ご覧のとおり、これはキーリスナーをフラグメントのルートビューに設定するため、フォーカスする必要があります。このクラスを拡張するフラグメント(または他の同じ内部フラグメントまたはビュー)に含まれる編集テキスト(または他のフォーカススティーリングビュー)がある場合は、個別に処理する必要があります。EditTextを拡張してバックプレスに集中できなくなる良い記事があります。
誰かがこれが役に立つと思うことを願っています。ハッピーコーディング。
super.onBackPressed();
二度電話するの?
currentFragment
。フラグメントがnull Backable
ではなく、フラグメントがインターフェースを実装している場合、アクションは実行されません。フラグメントがnullではなく、それが実装されていない場合はBackable
、superメソッドを呼び出します。フラグメントがnullの場合、最後のスーパーコールにスキップします。
currentFragment
がnullではなく、Backableのインスタンスであり、デタッチされている場合(back
ボタンを押してフラグメントを閉じた)、最初に出現したものsuper.onBackPressed();
が呼び出され、次に2番目が呼び出されます。
解決策は簡単です:
1)すべてのフラグメントが拡張する基本フラグメントクラスがある場合は、このコードをそのクラスに追加します。そうでない場合は、そのような基本フラグメントクラスを作成します
/*
* called when on back pressed to the current fragment that is returned
*/
public void onBackPressed()
{
// add code in super class when override
}
2)Activityクラスで、onBackPressedを次のようにオーバーライドします。
private BaseFragment _currentFragment;
@Override
public void onBackPressed()
{
super.onBackPressed();
_currentFragment.onBackPressed();
}
3)フラグメントクラスに、必要なコードを追加します。
@Override
public void onBackPressed()
{
setUpTitle();
}
onBackPressed()
フラグメントをアクティビティから切り離します。
@Sterling Diazの回答によると、彼は正しいと思います。しかし、いくつかの状況は間違っています。(例:画面の回転)
それで、isRemoving()
目標を達成するかどうかを検出できたと思います。
onDetach()
またはで記述できますonDestroyView()
。仕事です。
@Override
public void onDetach() {
super.onDetach();
if(isRemoving()){
// onBackPressed()
}
}
@Override
public void onDestroyView() {
super.onDestroyView();
if(isRemoving()){
// 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?
}
次に、アクティビティのonBackPressedをオーバーライドします
@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;
}
以下のようにプロジェクトにインターフェイスを追加する必要があります。
public interface OnBackPressed {
void onBackPressed();
}
次に、このインターフェイスをフラグメントに実装する必要があります。
public class SampleFragment extends Fragment implements OnBackPressed {
@Override
public void onBackPressed() {
//on Back Pressed
}
}
また、このonBackPressedイベントは、以下のようなアクティビティの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();
}
}
getActivity().onBackPressed();
「java.lang.StackOverflowError:スタックサイズ8MB」という例外が呼び出されるため、呼び出さないでください。
これは、トリックを実行する小さなコードです。
getActivity().onBackPressed();
それが誰かを助けることを願っています:)
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();
}
そしてあなたのActivityクラスであなたは定義することができます:
@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 MyFragment extends Fragment {
@Override
public void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
// This callback will only be called when MyFragment is at least Started.
OnBackPressedCallback callback = new OnBackPressedCallback(true /* enabled by default */) {
@Override
public void handleOnBackPressed() {
// Handle the back button event
}
});
requireActivity().getOnBackPressedDispatcher().addCallback(this, callback);
// The callback can be enabled or disabled here or in handleOnBackPressed()
}
...
}
コトリン
class MyFragment : Fragment() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
// This callback will only be called when MyFragment is at least Started.
val callback = requireActivity().onBackPressedDispatcher.addCallback(this) {
// Handle the back button event
}
// The callback can be enabled or disabled here or in the lambda
}
...
}
onDestroyView()を使用するのはどうですか?
@Override
public void onDestroyView() {
super.onDestroyView();
}
i = i
or と同じif (1 < 0) {}
です。
@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;
}
});
}
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;
}
}
私の解決策(Kotlin)では、
私は上のパラメータとしてonBackAlternative機能を使用していBaseActivity。
BaseActivity
abstract class BaseActivity {
var onBackPressAlternative: (() -> Unit)? = null
override fun onBackPressed() {
if (onBackPressAlternative != null) {
onBackPressAlternative!!()
} else {
super.onBackPressed()
}
}
}
BaseFragmentにonBackPressAlternativeを設定する関数があります。
BaseFragment
abstract class BaseFragment {
override fun onStart() {
super.onStart()
...
setOnBackPressed(null) // Add this
}
//Method must be declared as open, for overriding in child class
open fun setOnBackPressed(onBackAlternative: (() -> Unit)?) {
(activity as BaseActivity<*, *>).onBackPressAlternative = onBackAlternative
}
}
これで、onBackPressAlternativeがフラグメントで使用できるようになりました。
サブフラグメント
override fun setOnBackPressed(onBackAlternative: (() -> Unit)?) {
(activity as BaseActivity<*, *>).onBackPressAlternative = {
// TODO Your own custom onback function
}
}
ft.addToBackStack()メソッドを実装しないでください。そうすると、戻るボタンを押したときにアクティビティが終了します。
proAddAccount = new ProfileAddAccount();
FragmentManager fragmentManager = getSupportFragmentManager();
FragmentTransaction fragmentTransaction = fragmentManager.beginTransaction();
fragmentTransaction.replace(R.id.fragment_container, proAddAccount);
//fragmentTransaction.addToBackStack(null);
fragmentTransaction.commit();
次の手順に従ってください。
常にフラグメントを追加している間、
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()
}
それでおしまい!
アクティビティのライフサイクルでは、FragmentActivityまたはAppCompatActivityを使用した場合、常にAndroidの戻るボタンがFragmentManagerトランザクションを処理します。
バックスタックを処理するために、バックスタックカウントを処理したり、何かにタグ付けしたりする必要はありませんが、フラグメントを追加または置換する間、フォーカスを維持する必要があります。戻るボタンのケースを処理するには、次のスニペットを見つけてください。
public void replaceFragment(Fragment fragment) {
FragmentTransaction transaction = getSupportFragmentManager().beginTransaction();
if (!(fragment instanceof HomeFragment)) {
transaction.addToBackStack(null);
}
transaction.replace(R.id.activity_menu_fragment_container, fragment).commit();
}
ここでは、ホームフラグメントがアプリケーションのホームページであるため、ホームフラグメントにバックスタックを追加しません。addToBackStackをHomeFragmentに追加した場合、アプリは活動中のすべてのフレームを削除するのを待機し、空白の画面が表示されるため、次の条件を維持します。
if (!(fragment instanceof HomeFragment)) {
transaction.addToBackStack(null);
}
これで、以前に追加したacitvityのフラグメントを確認でき、HomeFragmentに到達するとアプリが終了します。次のスニペットもご覧ください。
@Override
public void onBackPressed() {
if (mDrawerLayout.isDrawerOpen(Gravity.LEFT)) {
closeDrawer();
} else {
super.onBackPressed();
}
}
フラグメント: メソッドを配置するBaseFragmentを作成します。
public boolean onBackPressed();
アクティビティ:
@Override
public void onBackPressed() {
List<Fragment> fragments = getSupportFragmentManager().getFragments();
if (fragments != null) {
for (Fragment fragment : fragments) {
if (!fragment.isVisible()) continue;
if (fragment instanceof BaseFragment && ((BaseFragment) fragment).onBackPressed()) {
return;
}
}
}
super.onBackPressed();
}
アクティビティは、アタッチされた可視フラグメントに対して実行され、それぞれのフラグメントでonBackPressed()を呼び出し、それらの1つが「true」を返した場合は処理を中止します(処理されたため、それ以上のアクションは行われません)。
よるとAndroidXのリリースノート、androidx.activity 1.0.0-alpha01
リリースされ、紹介されComponentActivity
、既存の新しい基本クラスFragmentActivity
とAppCompatActivity
。そしてこのリリースは私たちに新機能をもたらします:
OnBackPressedCallback
ビアaddOnBackPressedCallback
を登録してonBackPressed()
、アクティビティのメソッドをオーバーライドする必要なくコールバックを受信できるようになりました。
フラグメントをアクティビティに登録して、バックプレスを処理できます。
interface BackPressRegistrar {
fun registerHandler(handler: BackPressHandler)
fun unregisterHandler(handler: BackPressHandler)
}
interface BackPressHandler {
fun onBackPressed(): Boolean
}
使用法:
private val backPressHandler = object : BackPressHandler {
override fun onBackPressed(): Boolean {
showClosingWarning()
return false
}
}
override fun onResume() {
super.onResume()
(activity as? BackPressRegistrar)?.registerHandler(backPressHandler)
}
override fun onStop() {
(activity as? BackPressRegistrar)?.unregisterHandler(backPressHandler)
super.onStop()
}
class MainActivity : AppCompatActivity(), BackPressRegistrar {
private var registeredHandler: BackPressHandler? = null
override fun registerHandler(handler: BackPressHandler) { registeredHandler = handler }
override fun unregisterHandler(handler: BackPressHandler) { registeredHandler = null }
override fun onBackPressed() {
if (registeredHandler?.onBackPressed() != false) super.onBackPressed()
}
}
onBackPressedを処理してカスタムの戻るナビゲーションを提供することは、フラグメント内のコールバックにより簡単になりました。
class MyFragment : Fragment() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
val onBackPressedCallback = object : OnBackPressedCallback(true) {
override fun handleOnBackPressed() {
if (true == conditionForCustomAction) {
myCustomActionHere()
} else NavHostFragment.findNavController(this@MyFragment).navigateUp();
}
}
requireActivity().onBackPressedDispatcher.addCallback(
this, onBackPressedCallback
)
...
}
なんらかの条件に基づくデフォルトのバックアクションが必要な場合は、以下を使用できます。
NavHostFragment.findNavController(this@MyFragment).navigateUp();
フラグメントのonCreateメソッド内に以下を追加します。
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
OnBackPressedCallback callback = new OnBackPressedCallback(true) {
@Override
public void handleOnBackPressed() {
//Handle the back pressed
}
};
requireActivity().getOnBackPressedDispatcher().addCallback(this, callback);
}
最良のソリューション、
import android.support.v4.app.Fragment;
import android.support.v4.app.FragmentManager;
import android.support.v7.app.AppCompatActivity;
public class BaseActivity extends AppCompatActivity {
@Override
public void onBackPressed() {
FragmentManager fm = getSupportFragmentManager();
for (Fragment frag : fm.getFragments()) {
if (frag == null) {
super.onBackPressed();
finish();
return;
}
if (frag.isVisible()) {
FragmentManager childFm = frag.getChildFragmentManager();
if (childFm.getFragments() == null) {
super.onBackPressed();
finish();
return;
}
if (childFm.getBackStackEntryCount() > 0) {
childFm.popBackStack();
return;
}
else {
fm.popBackStack();
if (fm.getFragments().size() <= 1) {
finish();
}
return;
}
}
}
}
}