有没有一种方法可以onBackPressed()
在 Android Fragment 中实现类似于我们在 Android Activity 中实现的方式?
由于 Fragment 生命周期没有onBackPressed()
. 是否有任何其他替代方法可以覆盖onBackPressed()
Android 3.0 片段?
有没有一种方法可以onBackPressed()
在 Android Fragment 中实现类似于我们在 Android Activity 中实现的方式?
由于 Fragment 生命周期没有onBackPressed()
. 是否有任何其他替代方法可以覆盖onBackPressed()
Android 3.0 片段?
我通过这种方式解决了Activity中的override 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
}
}
}
如果您正在使用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
根据@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;
创建方法来设置监听器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;
}
瞧,现在当您在片段中单击返回时,您应该捕获自定义的返回方法。
这对我有用: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 是一个更加解耦的实现,并且可以更好地扩展,所以这将是我现在的官方实现建议。只需使用Intent
' 操作作为您的消息的过滤器。发送您新创建ACTION_BACK_PRESSED
的,从您的活动中发送并在相关片段中收听。
这些都不容易实现,也不会以最佳方式运行。
片段有一个方法调用 onDetach 可以完成这项工作。
@Override
public void onDetach() {
super.onDetach();
PUT YOUR CODE HERE
}
这样就可以了。
onBackPressed
Google 发布了一个新的 API来处理Fragment
:
activity?.onBackPressedDispatcher?.addCallback(viewLifecycleOwner, object : OnBackPressedCallback(true) {
override fun handleOnBackPressed() {
}
})
只需addToBackStack
在片段之间转换时添加,如下所示:
fragmentManager.beginTransaction().replace(R.id.content_frame,fragment).addToBackStack("tag").commit();
如果你写addToBackStack(null)
,它会自己处理它,但如果你给一个标签,你应该手动处理它。
爪哇
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
}
...
}
新的更好的方法:遵循 a 中的一段代码Fragment
将帮助您捕获 back-press 事件。
爪哇
@Override
public void onAttach(@NonNull Context context) {
super.onAttach(context);
OnBackPressedCallback callback = new OnBackPressedCallback(true) {
@Override
public void handleOnBackPressed() {
Toast.makeText(mContext, "back pressed", Toast.LENGTH_SHORT).show();
// And when you want to go back based on your condition
if (yourCondition) {
this.setEnabled(false);
requireActivity().onBackPressed();
}
}
};
requireActivity().getOnBackPressedDispatcher().addCallback(this, callback);
}
科特林
activity?.onBackPressedDispatcher?.addCallback(viewLifecycleOwner, object : OnBackPressedCallback(true) {
override fun handleOnBackPressed() {
}
})
由于这个问题和一些答案已经超过五年了,让我分享我的解决方案。这是@oyenigun 答案的后续和现代化
更新: 在本文的底部,我添加了一个使用抽象片段扩展的替代实现,它根本不涉及活动,这对于任何具有更复杂片段层次结构的人都非常有用,其中涉及需要不同返回行为的嵌套片段。
我需要实现这一点,因为我使用的一些片段具有较小的视图,我想用后退按钮关闭它们,例如弹出的小信息视图等,但这对于需要覆盖的行为的任何人都有好处片段内的后退按钮。
首先,定义一个接口
public interface Backable {
boolean onBackPressed();
}
这个接口,我称之为Backable
(我是命名约定的坚持者),有一个onBackPressed()
必须返回boolean
值的方法。我们需要强制一个布尔值,因为我们需要知道按下后退按钮是否“吸收”了后退事件。Returningtrue
表示它已经完成,不需要进一步的操作,否则,false
表示仍然必须执行默认的返回操作。这个接口应该是它自己的文件(最好在一个名为 的单独包中interfaces
)。请记住,将类分成包是一种很好的做法。
二、找到最上面的fragment
我创建了一个方法,该方法返回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
可能会在运行时抛出 an。如果不大于 0,则返回 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,表明您的后退事件已被吸收。否则,返回假。
最后,在您的活动中...
覆盖该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();
}
我们在后台堆栈中获取当前片段,然后我们进行空检查并确定它是否实现了我们的Backable
接口。如果是,请确定该事件是否已被吸收。如果是这样,我们已经完成onBackPressed()
并且可以返回。否则,将其视为正常的后按并调用 super 方法。
不参与活动的第二种选择
有时,您根本不希望 Activity 处理此问题,您需要直接在片段中处理它。但是谁说你不能有带有 back press API 的 Fragments 呢?只需将您的片段扩展到一个新类。
创建一个扩展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。如果您对后退按钮所做的任何事情都不需要处理,请确保您确实调用了 ActivityonBackPressed()
方法,否则,后退按钮将被禁用......而且您不希望这样!
注意事项 如您所见,这会将关键侦听器设置为片段的根视图,我们需要关注它。如果扩展此类的片段(或具有相同内容的其他内部片段或视图)中涉及编辑文本(或任何其他窃取焦点的视图),则需要单独处理。有一篇关于扩展 EditText以失去对背压的关注的好文章。
我希望有人觉得这很有用。快乐编码。
解决方案很简单:
/*
* called when on back pressed to the current fragment that is returned
*/
public void onBackPressed()
{
// add code in super class when override
}
onBackPressed
如下:private BaseFragment _currentFragment;
@Override
public void onBackPressed()
{
super.onBackPressed();
_currentFragment.onBackPressed();
}
@Override
public void onBackPressed()
{
setUpTitle();
}
onBackPressed()
导致 Fragment 与 Activity 分离。
根据@Sterling Diaz 的回答,我认为他是对的。但是有些情况会出错。(例如旋转屏幕)
所以,我认为我们可以检测是否isRemoving()
实现了目标。
你可以写在onDetach()
或onDestroyView()
。这是工作。
@Override
public void onDetach() {
super.onDetach();
if(isRemoving()){
// onBackPressed()
}
}
@Override
public void onDestroyView() {
super.onDestroyView();
if(isRemoving()){
// onBackPressed()
}
}
在片段的 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);
}
如果您使用 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;
}
});
好吧,我这样做了,它对我有用
简单的界面
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();
}
}
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;
}
}
这只是一个可以解决问题的小代码:
getActivity().onBackPressed();
希望它可以帮助某人:)
requireActivity().onBackPressedDispatcher.addCallback(viewLifecycleOwner) {
//your code
}
您可以onBackPressedDispatcher
像这样使用父活动:
val backpress = requireActivity().onBackPressedDispatcher.addCallback(viewLifecycleOwner, true) {
// here dispatcher works for any action when back pressed
}
您还可以随时从片段启用/禁用后按按钮,如下所示:
backpress.isEnabled = true/false
@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;
}
});
}
使用 onDestroyView() 怎么样?
@Override
public void onDestroyView() {
super.onDestroyView();
}
非常简短而甜蜜的答案:
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,您可以简单地放入getActivity().onBackPressed();
FragmentB。
在我的解决方案(Kotlin)中;
我使用 onBackAlternative 函数作为 BaseActivity 的参数。
基本活动
abstract class BaseActivity {
var onBackPressAlternative: (() -> Unit)? = null
override fun onBackPressed() {
if (onBackPressAlternative != null) {
onBackPressAlternative!!()
} else {
super.onBackPressed()
}
}
}
我有一个在 BaseFragment 上设置onBackPressAlternative的功能。
基本片段
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
}
}
根据AndroidX 发布说明,androidx.activity 1.0.0-alpha01
发布并介绍ComponentActivity
了现有的新基类FragmentActivity
和AppCompatActivity
. 而这个版本为我们带来了一个新功能:
您现在可以注册一个OnBackPressedCallback
viaaddOnBackPressedCallback
来接收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();
只需按照以下步骤操作:
总是在添加片段时,
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()
}
而已!
不要实现 ft.addToBackStack() 方法,这样当您按下返回按钮时,您的活动将完成。
proAddAccount = new ProfileAddAccount();
FragmentManager fragmentManager = getSupportFragmentManager();
FragmentTransaction fragmentTransaction = fragmentManager.beginTransaction();
fragmentTransaction.replace(R.id.fragment_container, proAddAccount);
//fragmentTransaction.addToBackStack(null);
fragmentTransaction.commit();
在活动生命周期中,当我们使用 FragmentActivity 或 AppCompatActivity 时,总是 android 后退按钮处理 FragmentManager 事务。
要处理 backstack,我们不需要处理它的 backstack 计数或标记任何内容,但我们应该在添加或替换片段时保持焦点。请找到以下片段来处理后退按钮的情况,
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);
}
现在,您可以在活动中看到之前添加的片段,并且应用程序将在到达 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()并在其中一个返回“真”时中止(意味着它已被处理,因此没有进一步的操作)。
在 kotlin 中,它更简单。
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
requireActivity().onBackPressedDispatcher.addCallback(viewLifecycleOwner, object : OnBackPressedCallback(true) {
override fun handleOnBackPressed() {
//
}
})
}
您可以在活动中注册片段以处理后按:
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()
}
}
从您的片段中,只需使用
requireActivity().onBackPressed();
对于处理点击添加 binding.actionABack.setOnClickListener(v -> requireActivity().onBackPressed());
最佳解决方案,
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;
}
}
}
}
}
如果你有一个 Activity A 并且你制作了 B、C 和 D 等 3 个片段,这很简单。现在,如果你在片段 B 或 C 中,并且onBackPressed
你想每次都在片段 D 上移动。那么你必须覆盖中的onBackPressed()
方法主要活动 A 以及当您跳转到任何片段时,然后传递该片段的标签或名称 ,您可以通过该标签或名称在主要活动 A 中识别该片段。
我举一个例子,你可以很容易地理解......
if (savedInstanceState == null) {
getSupportFragmentManager().beginTransaction().add(R.id.container, new C_fragment(),"xyz").commit();
}
或者,如果您要从片段 B 移动到片段 C..并且在后按时您想进入片段 D ...如下所示
btn.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
getActivity().getSupportFragmentManager().beginTransaction().add(R.id.container, new C_frament(), "xyz").commit();
((ActionBarActivity) getActivity()).getSupportActionBar().setTitle("Fragment C");
}
});
现在您必须在主要活动中覆盖 onBackPressed() 方法..如下所示..
@Override
public void onBackPressed() {
FragmentManager fragmentManager =getSupportFragmentManager();
if (((C_fragment) getSupportFragmentManager().findFragmentByTag("xyz")) != null && ((C_fragment) getSupportFragmentManager().findFragmentByTag("xyz")).isVisible()) {
Fragment fragment = new D_Fragment();
fragmentManager.beginTransaction().replace(R.id.container, fragment).commit();
getSupportActionBar().setTitle("D fragment ");
} else {
super.onBackPressed();
}
}
如果您需要在 Fragment 中实现,您应该使用 interface。
另一方面,如果您需要在活动中实现,例如。执行一个简单finish()
的活动,执行以下操作:
override fun onBackPressed() {
Log.d(this.javaClass.simpleName, "onBackPressed() called")
if (supportFragmentManager.fragments.any { it is YourFragment }) {
finish()
return
}
}
好吧,伙计们,我终于找到了一个好的解决方案。
在您的活动中的 onCreate() 中,您的片段添加一个 backstack 更改侦听器,如下所示:
fragmentManager.addOnBackStackChangedListener(new FragmentManager.OnBackStackChangedListener() {
@Override
public void onBackStackChanged() {
List<Fragment> f = fragmentManager.getFragments();
//List<Fragment> f only returns one value
Fragment frag = f.get(0);
currentFragment = frag.getClass().getSimpleName();
}
});
(另外添加我的 fragmenManager 在活动中声明 O 现在每次更改片段时,当前片段字符串将成为当前片段的名称。然后在活动 onBackPressed() 中,您可以控制后退按钮的操作,如下所示:
@Override
public void onBackPressed() {
switch (currentFragment) {
case "FragmentOne":
// your code here
return;
case "FragmentTwo":
// your code here
return;
default:
fragmentManager.popBackStack();
// default action for any other fragment (return to previous)
}
}
我可以确认这种方法对我有用。
这是我处理按下后退按钮上的片段的答案。我有五个项目(A、B、C、D、E)的底部导航,当单击我将片段附加到活动的项目时附加到活动。假设单击项目(A)我附加片段(A)然后如果单击项目(B)然后我附加片段(B)等等。
点击项的流程。A->B->C->D->E
按下后退按钮的流程。E->D->C->B->A
@Override
public void onBackPressed() {
int count = getSupportFragmentManager().getBackStackEntryCount();
if (count == 0) {
super.onBackPressed();
} else {
int index = ((getSupportFragmentManager().getBackStackEntryCount()) -1);
getSupportFragmentManager().popBackStack();
FragmentManager.BackStackEntry backEntry = getSupportFragmentManager().getBackStackEntryAt(index);
int stackId = backEntry.getId();
bottomNavigationView.getMenu().getItem(stackId).setChecked(true);
}
}
只需在 onKeyUp() 中执行:
@Override
public boolean onKeyUp(int keyCode, KeyEvent event) {
if (keyCode == KeyEvent.KEYCODE_BACK) {
// do something
return true; // return true if back handled, false otherwise
}
return super.onKeyUp(keyCode, event);
}
我知道为时已晚,但上周我遇到了同样的问题。没有一个答案对我有帮助。然后我在玩代码,这很有效,因为我已经添加了片段。
在您的活动中,为 设置一个OnPageChangeListener
,ViewPager
以便您知道用户何时处于第二个活动中。如果他在第二个活动中,请true
按如下方式进行布尔值:
mSectionsPagerAdapter = new SectionsPagerAdapter(getSupportFragmentManager());
// Set up the ViewPager with the sections adapter.
mViewPager = (ViewPager) findViewById(R.id.pager);
mViewPager.setAdapter(mSectionsPagerAdapter);
mViewPager.setCurrentItem(0);
mViewPager.addOnPageChangeListener(new OnPageChangeListener() {
@Override
public void onPageSelected(int position) {
// TODO Auto-generated method stub
mSectionsPagerAdapter.instantiateItem(mViewPager, position);
if(position == 1)
inAnalytics = true;
else if(position == 0)
inAnalytics = false;
}
@Override
public void onPageScrolled(int position, float arg1, int arg2) {
// TODO Auto-generated method stub
}
@Override
public void onPageScrollStateChanged(int arg0) {
// TODO Auto-generated method stub
}
});
现在在按下后退按钮时检查布尔值并将当前项目设置为您的第一个片段:
@Override
public void onBackPressed() {
if(inAnalytics)
mViewPager.setCurrentItem(0, true);
else
super.onBackPressed();
}
如果你真的想在 Fragment 中启用 onBackPressed(),试试这个。 在浪费了一个小时的时间之后,根据我以前的经验,我制作了这个完全符合需求的解决方案。
您只需要关注满足片段private int STATUS_FRAGMENT=0;
需求的值即可。addToBackStack()
import android.view.MenuItem;
import android.view.View;
import androidx.annotation.NonNull;
import androidx.appcompat.app.AppCompatActivity;
import androidx.fragment.app.Fragment;
import com.example.growfast.NavigationItemsFolder.CoreFragments.Cart;
import com.example.growfast.NavigationItemsFolder.CoreFragments.HelpDesk;
import com.example.growfast.NavigationItemsFolder.CoreFragments.Home;
import com.example.growfast.NavigationItemsFolder.CoreFragments.ProfileDetails;
import com.example.growfast.R;
import com.google.android.material.bottomnavigation.BottomNavigationView;
public class BusinessManagement extends AppCompatActivity {
public BottomNavigationView bottomNavigationView;
private int STATUS_FRAGMENT=0;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_base_layout);
setBottomNavigationMenu();
}
private void setBottomNavigationMenu() {
bottomNavigationView = findViewById(R.id.navigation);
bottomNavigationView.setVisibility(View.VISIBLE);
bottomNavigationView.setOnNavigationItemSelectedListener(new BottomNavigationView.OnNavigationItemSelectedListener() {
Fragment fragment = null;
@Override
public boolean onNavigationItemSelected(@NonNull MenuItem item) {
switch (item.getItemId()) {
case R.id.action_home:
fragment = new Home();
break;
case R.id.action_profile:
fragment = new ProfileDetails();
break;
case R.id.action_cart:
fragment = new Cart();
break;
case R.id.action_favourites_menu:
fragment = new HelpDesk();
break;
}
return loadFromFragment(fragment);
}
});
bottomNavigationView.setSelectedItemId(R.id.action_home);
}
private boolean loadFromFragment(Fragment fragment) {
if (fragment != null) {
getSupportFragmentManager().beginTransaction().replace(R.id.my_container, fragment)
.commit();
STATUS_FRAGMENT=1;
return true;
}
return false;
}
@Override
public void onBackPressed() {
if (STATUS_FRAGMENT==1) {
bottomNavigationView.setSelectedItemId(R.id.action_home);
STATUS_FRAGMENT=0;
bottomNavigationView.setVisibility(View.VISIBLE);
}
else{
super.onBackPressed();
}
}
}```
我使用了另一种方法,如下所示:
Runnable
onBackPressed
控制 Activity 中调用时,它会弹出最近的自定义返回操作并执行其Runnable
. 如果堆栈上没有任何内容,super.onBackPressed()
则调用默认值此处包含示例代码的完整方法,作为对其他 SO question的回答。
private boolean isMainFragment = true;
@Override
public void onBackPressed() {
if (isMainFragment){
finish();
}else {
getSupportFragmentManager().popBackStack();
isMainFragment = true;
}
}
当打开花药片段时,只需添加
isMainFragment = false;
这是我的工作
在你的 mainActivity 实现回调接口
protected mainActivity.OnBackPressedListener onBackPressedListener;
public interface OnBackPressedListener {
void doBack();
}
public void setOnBackPressedListener(mainActivity.OnBackPressedListener onBackPressedListener) {
this.onBackPressedListener = onBackPressedListener;
}
@Override
public void onBackPressed() {
if (onBackPressedListener != null) {
onBackPressedListener.doBack();
} else {
super.onBackPressed();
}
}
在片段上实现我们在 mainActivity 中编写的接口 OnBackPressedListener
implements mainActivity.OnBackPressedListener
mainActivity 是我的基本活动,在您的片段 onCreateView 方法中编写以下代码
((mainActivity) getActivity()).setOnBackPressedListener(this);
并实现 OnBackPressedListener 接口方法 doBack
@Override
public void doBack() {
//call base fragment
}
现在使用 doBack() 方法调用您想要调用的片段
没有人提到我如何activity?.onBackPressed
在这个逻辑中调用。
所以我创建了一个可能对你有用的扩展:
fun Fragment.onBackClick(callback: (onBackPressedCallback: OnBackPressedCallback) -> Unit) {
// This callback will only be called when MyFragment is at least Started.
activity?.onBackPressedDispatcher?.addCallback(viewLifecycleOwner) {
callback.invoke(this)
}
}
onBackPressed
现在,当您的逻辑完成时,令人兴奋的部分调用:
片段中的示例使用:
onBackClick {
if (shouldBackFromFrag){
//do your logic when pressed back
}else{
it.isEnabled = false //the key to disable the dispatcher
activity?.onBackPressed()
}
}
我有同样的问题,我为它创建了一个新的监听器并在我的片段中使用。
1 - 你的活动应该有一个监听器接口和一个监听器列表
2 - 您应该实现添加和删除侦听器的方法
3 - 您应该重写 onBackPressed 方法以检查是否有任何侦听器使用后按
public class MainActivity ... {
/**
* Back press listener list. Used for notifying fragments when onBackPressed called
*/
private Stack<BackPressListener> backPressListeners = new Stack<BackPressListener>();
...
/**
* Adding new listener to back press listener stack
* @param backPressListener
*/
public void addBackPressListener(BackPressListener backPressListener) {
backPressListeners.add(backPressListener);
}
/**
* Removing the listener from back press listener stack
* @param backPressListener
*/
public void removeBackPressListener(BackPressListener backPressListener) {
backPressListeners.remove(backPressListener);
}
// Overriding onBackPressed to check that is there any listener using this back press
@Override
public void onBackPressed() {
// checks if is there any back press listeners use this press
for(BackPressListener backPressListener : backPressListeners) {
if(backPressListener.onBackPressed()) return;
}
// if not returns in the loop, calls super onBackPressed
super.onBackPressed();
}
}
4 - 您的片段必须实现后按接口
5 - 您需要将片段添加为后按的侦听器
6 - 如果片段使用此后按,您应该从 onBackPressed 返回 true
7 - 重要 - 您必须从 onDestroy 列表中删除片段
public class MyFragment extends Fragment implements MainActivity.BackPressListener {
...
@Override
public void onAttach(Activity activity) {
super.onCreate(savedInstanceState);
// adding the fragment to listener list
((MainActivity) activity).addBackPressListener(this);
}
...
@Override
public void onDestroy() {
super.onDestroy();
// removing the fragment from the listener list
((MainActivity) getActivity()).removeBackPressListener(this);
}
...
@Override
public boolean onBackPressed() {
// you should check that if this fragment is the currently used fragment or not
// if this fragment is not used at the moment you should return false
if(!isThisFragmentVisibleAtTheMoment) return false;
if (isThisFragmentUsingBackPress) {
// do what you need to do
return true;
}
return false;
}
}
使用 Stack 代替 ArrayList 可以从最新的片段开始。将片段添加到后台堆栈时也可能存在问题。因此,您需要在使用后按时检查片段是否可见。否则其中一个片段将使用该事件,并且最新片段不会在后按时关闭。
我希望这可以解决每个人的问题。
我只是使用findFragmentById
并转换到片段并调用处理 onBackpressed 的方法。此示例显示检查这是否是订单流程中的第一步,如果弹出对话框片段以确认退出订单。
@Override
public void onBackPressed() {
//check if first fragment in wizard is loaded, if true get abandon confirmation before going back
OrderFragment frag =(OrderFragment)getSupportFragmentManager().findFragmentById(R.id.fragContainer);
if (frag==null || (frag!=null && frag.getOrderStage()<1)){
AlertDialogFragment.show(getSupportFragmentManager(), R.string.dialog_cancel_order,R.string.dialog_cancel_order_msg, R.string.dialog_cancel_order_pos,R.string.dialog_order_quiz_neg, DIALOG_ID_CANCEL);
}else {
super.onBackPressed();
}
}
@Override
public boolean onKeyDown(int keyCode, KeyEvent event)
{
if ((keyCode == KeyEvent.KEYCODE_BACK))
{
finish();
}
return super.onKeyDown(keyCode, event);
}
只需评论任何 Key down 相关的方法现在 addToBackStack 将起作用。谢谢
这行代码将在任何片段中执行此操作,它将当前片段弹出回栈。
getActivity().getSupportFragmentManager().popBackStack();
在 Fragments中处理onBackPressed()的简单方法
第 1 步: 在活动中创建一个静态布尔值。
public static Fragment_one;
步骤 2: 在 On Create 方法中的 MainActivity(包含片段的活动)上,声明
Fragment_one=true;
第 3 步:覆盖 MainActivity 中的 onBackPressed()
@Override
public void onBackPressed() {
if(Fragment_one) {
//Back key pressed on fragment one
}else {
//Back key pressed on fragment two
}
}
第 4 步:在 fragment_one 的 onCreateView方法上声明
MainActivity.Fragment_one=true;
第 5 步 在 fragment_two 的 onCreateView方法上声明
MainActivity.Fragment_one=false;
注意:此方法仅适用于两个片段。
像这样实现 Fragment_1 -> Fragment_2 -> Fragment_3
Button btn = (Button) rootView.findViewById(R.id.your_button_id);
btn.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
Fragment_2 nextFrag= new Fragment_2();
getActivity().getSupportFragmentManager().beginTransaction()
.replace(R.id.content_frame, nextFrag,getTag())
.addToBackStack(null)
.commit();
}
});
Fragment_3 -> Fragment_2 -> Fragment_1
Step_1:在基本活动中创建一个可公开访问的字符串
Step_2:每当一个新的Fragment被激活时,改变Base Activity中String的值
Step_3:然后添加 onBackPressed() 方法并将String值传递给另一个可以替换fagments的方法
在基础活动中
public static String currentFragment=null;
@Override
public void onBackPressed()
{
displayPreviousFragment(currentFragment);
}
public void displayPreviousFragment(String currentFragment)
{
//creating fragment object
Fragment fragment = null;
//initializing the fragment object which is selected
switch (currentFragment)
{
case "Fragment_2" : fragment = new Fargment_1(); break;
case "Fragment_3" : fragment = new Fragment_2(); break;
}
//replacing the fragment
if (fragment != null) {
FragmentTransaction ft = getSupportFragmentManager().beginTransaction();
ft.replace(R.id.frame_to_replace_fragment, fragment);
ft.commit();
}
}
在 OnCreateView 方法里面的 Fragment_2
BaseActivity.currentFragment="Fragment_2";
在 OnCreateView 方法里面的 Fragment_3
BaseActivity.currentFragment="Fragment_3";
public interface IonBackPressInFrag {
void backPressed();
}
public class FragmentMainActivity extends AppCompatActivity {
public IonBackPressInFrag backPressInFrag;
@Override
protected void onCreate(Bundle savedInstanceState) {
@Override
public void onBackPressed () {
backPressInFrag.backPressed();
}
}
}
public class FragDetailSearch extends Fragment implements IonBackPressInFrag {
if(getActivity() !=null){
((FragmentMainActivity) getActivity()).backPressInFrag = this;
}
@Override
public void backPressed() {
Toast.makeText(getContext(), "backkkkkk", Toast.LENGTH_LONG).show();
}
}
这是我对该问题的解决方案:
在活动 A 中:
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data)
{
super.onActivityResult(requestCode, resultCode, data);
if(requestCode == REQUEST_CODE)
{
if(resultCode == Activity.RESULT_OK)
{
tvTitle.setText(data.getExtras().getString("title", ""));
}
}
}
在活动 B 中:
@Override
public void onBackPressed()
{
setResult(Activity.RESULT_OK, getIntent());
super.onBackPressed();
}
活动 b 持有该片段。
在片段中:
private void setText(String text)
{
Intent intent = new Intent();
intent.putExtra("title", text);
getActivity().setIntent(intent);
}
这样,活动 A 中的意图对象“数据”将从片段中获取字符串