是否有一种方法,我们可以实现onBackPressed()在Android片段类似的方式,我们实现在Android活动?
因为Fragment的生命周期没有onBackPressed()。在android3.0片段中是否有其他替代方法来覆盖onBackPressed() ?
是否有一种方法,我们可以实现onBackPressed()在Android片段类似的方式,我们实现在Android活动?
因为Fragment的生命周期没有onBackPressed()。在android3.0片段中是否有其他替代方法来覆盖onBackPressed() ?
当前回答
谷歌发布了一个新的API来处理碎片中的onBackPressed:
activity?.onBackPressedDispatcher?.addCallback(viewLifecycleOwner, object : OnBackPressedCallback(true) {
override fun handleOnBackPressed() {
}
})
其他回答
既然这个问题和一些答案已经超过5年了,让我分享一下我的解决方案。这是@oyenigun的回答的后续和现代化
更新: 在本文的底部,我添加了一个使用抽象Fragment扩展的替代实现,它根本不涉及Activity,这对于任何具有更复杂的片段层次结构(涉及需要不同返回行为的嵌套片段)的人来说都是有用的。
我需要实现这一点,因为我使用的一些片段具有较小的视图,我希望通过返回按钮来消除这些视图,例如弹出的小信息视图,等等,但这对于需要覆盖片段内返回按钮行为的任何人都是有益的。
首先,定义一个接口
public interface Backable {
boolean onBackPressed();
}
This interface, which I call Backable (I'm a stickler for naming conventions), has a single method onBackPressed() that must return a boolean value. We need to enforce a boolean value because we will need to know if the back button press has "absorbed" the back event. Returning true means that it has, and no further action is needed, otherwise, false says that the default back action still must take place. This interface should be it's own file (preferably in a separate package named interfaces). Remember, separating your classes into packages is good practice.
其次,找到顶部的片段
我创建了一个方法,返回后面堆栈中的最后一个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。稍后我们将检查空值…
第三,在一个片段中实现
在需要覆盖后退按钮行为的片段中实现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();
}
我们在back堆栈中获取当前片段,然后进行空检查并确定它是否实现了Backable接口。如果是,确定事件是否被吸收。如果是这样,我们就完成了onBackPressed()并可以返回。否则,将其视为普通的背压并调用super方法。
第二种选择是不参与活动
有时,您根本不希望Activity处理它,而需要直接在片段中处理它。但是谁说Fragments不能带有背压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的片段都会使用视图自动捕获回点击。OnKeyListener接口。只需在实现的onKey()方法中调用抽象的onBackButtonPressed()方法,使用标准逻辑来识别后退按钮的按下。如果你需要注册按键点击而不是返回按钮,只要确保在你的片段中覆盖onKey()时调用super方法,否则你将覆盖抽象中的行为。
使用简单,只需扩展和实现:
public class FragmentChannels extends BackableFragment {
...
@Override
public void onBackButtonPressed() {
if (doTheThingRequiringBackButtonOverride) {
// do the thing
} else {
getActivity().onBackPressed();
}
}
...
}
由于超类中的onBackButtonPressed()方法是抽象的,一旦扩展,就必须实现onBackButtonPressed()。它返回void,因为它只需要在fragment类中执行一个动作,而不需要将压力的吸收传递回Activity。如果你对后退按钮所做的事情不需要处理,请确保你调用Activity onBackPressed()方法,否则,后退按钮将被禁用…你不会想要这样的!
警告 如您所见,这将关键侦听器设置为片段的根视图,我们需要集中它。如果在扩展该类的片段(或具有相同内容的其他内部片段或视图)中涉及到编辑文本(或任何其他焦点窃取视图),则需要单独处理。有一篇很好的文章介绍了如何扩展EditText以使其失去对背压的关注。
我希望有人觉得这有用。快乐的编码。
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();
}
}
在我的解决方案(Kotlin);
我使用onBackAlternative函数作为BaseActivity的参数。
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
}
}
这只是一个小代码,可以做到这一点:
getActivity().onBackPressed();
希望它能帮助到别人:)
我只是使用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();
}
}