如何处理DialogFragment中的后退行为最佳方法?

8

我有一个显示区域选择列表的DialogFragment。一旦用户点击区域,该列表将重新获取数据以显示街道选择列表。此时,我希望允许用户按硬件返回按钮返回到区域选择。这可能吗?我尝试重写一些方法,但我只能触发事件而无法阻止它发生。

@Override
public void onCancel(DialogInterface dialog) {
    if(isDismissable()){
        super.onCancel(dialog);
    }else {
        Log.d(TAG, "Don't dismiss cancel this dialog!");
    }
}

@Override
public void dismissAllowingStateLoss() {
    if(isDismissable()){
        super.dismissAllowingStateLoss();
    }else {
        Log.d(TAG, "Don't dismiss this dialog!");
    }
}

@Override
public void dismiss() {
    if(isDismissable()){
        super.dismiss();
    }else {
        Log.d(TAG, "Don't dismiss this dialog!");
    }
}

dismiss()会在用户按下返回按钮时调用,但即使我不调用super.dismiss(),对话框也会被关闭。

有没有办法做到这一点?我还研究了一下Google+应用程序如何在DialogFragment中显示ActionBar以提供HomeAsUp,但我找不到任何相关信息。

3个回答

5
我看到两个解决方案:
最简单的方式:将区域选择和街道选择列表分别作为独立的常规片段,并将它们都放在一个单独的活动中,将此活动作为对话框通过简单主题展示:<activity android:theme="@android:style/Theme.Dialog" /> 然后使用excludeFromRecents="true"以使其不会出现在最近使用的应用程序中。首先加载区域选择,然后通过addToBackStack(null)添加街道选择,这样你就可以在下面拥有AreaSelection片段。
如果由于任何原因您不想为此创建单独的活动,则可以从对话框片段中添加对话框侦听器,而它的实现者(即活动)将打开AreaFragment。基于对你的代码的基本理解,这个简单的项目应该做到这一点:
所有者活动:
import com.example.adip.fragments.AreaSelectionFragment;
import com.example.adip.fragments.StreetSelectionFragment;
import com.example.adip.fragments.AreaSelectionFragment.AreaSelectionListener;
import com.example.adip.fragments.StreetSelectionFragment.StreetSelectionListener;

import android.os.Bundle;
import android.support.v4.app.DialogFragment;
import android.support.v4.app.FragmentActivity;
import android.view.View;
import android.view.View.OnClickListener;

public class DialogsActivity extends FragmentActivity implements OnClickListener,
        AreaSelectionListener, StreetSelectionListener {

    private static final String AREA_TAG = "AREA_TAG";

    private static final String STREETS_TAG = "STREETS_TAG";

    @Override
    protected void onCreate(Bundle savedInstance) {
        super.onCreate(savedInstance);
        setContentView(R.layout.area_selections);
        findViewById(R.id.btnStuff).setOnClickListener(this);
    }

    @Override
    public void onClick(View v) {
        showArea();
    }

    private void showArea() {
        DialogFragment df = new AreaSelectionFragment();
        df.show(getSupportFragmentManager(), AREA_TAG);
    }

    @Override
    public void onStreetsUserCanceled() {
        showArea();
    }

    @Override
    public void showStreets() {
        DialogFragment df = new StreetSelectionFragment();
        df.show(getSupportFragmentManager(), STREETS_TAG);
    }

}

AreaSelectionFragment(根据您的需求进行扩展):

import android.app.Activity;
import android.app.AlertDialog;
import android.app.Dialog;
import android.content.DialogInterface;
import android.content.DialogInterface.OnClickListener;
import android.os.Bundle;
import android.support.v4.app.DialogFragment;

public class AreaSelectionFragment extends DialogFragment {
    public static interface AreaSelectionListener {
        void showStreets();
    }

    private AreaSelectionListener areaSelectionListener;

    @Override
    public void onAttach(Activity activity) {
        super.onAttach(activity);
        if (activity instanceof AreaSelectionListener) {
            areaSelectionListener = (AreaSelectionListener) activity;
        } else {
            throw new ClassCastException("Parent Activity must implement AreaSelectionListener");
        }
    }

    @Override
    public void onDetach() {
        super.onDetach();
        areaSelectionListener = null;
    }

    @Override
    public Dialog onCreateDialog(Bundle savedInstanceState) {
        return new AlertDialog.Builder(getActivity()).setTitle("Area Selection")
                .setPositiveButton("OK", new OnClickListener() {

                    @Override
                    public void onClick(DialogInterface dialog, int which) {
                        areaSelectionListener.showStreets();
                    }
                }).setNegativeButton("Cancel", null).create();
    }
}

还有,StreetSelectionFragment(再次强调:根据您的需求进行扩展):

import android.app.Activity;
import android.app.AlertDialog;
import android.app.Dialog;
import android.content.DialogInterface;
import android.content.DialogInterface.OnClickListener;
import android.os.Bundle;
import android.support.v4.app.DialogFragment;

public class StreetSelectionFragment extends DialogFragment {
    public static interface StreetSelectionListener {
        void onStreetsUserCanceled();
    }

    private StreetSelectionListener selectionListener;

    @Override
    public void onAttach(Activity activity) {
        super.onAttach(activity);
        if (activity instanceof StreetSelectionListener) {
            selectionListener = (StreetSelectionListener) activity;
        } else {
            throw new ClassCastException("Parent activity must implement StreetSelectionListener");
        }
    }

    @Override
    public void onDetach() {
        selectionListener = null;
        super.onDetach();
    }

    @Override
    public Dialog onCreateDialog(Bundle savedInstanceState) {
        Dialog dialog = new AlertDialog.Builder(getActivity()).setTitle("Street Selection")
                .setPositiveButton("OK", null).setNegativeButton("Cancel", new OnClickListener() {

                    @Override
                    public void onClick(DialogInterface dialog, int which) {
                        selectionListener.onStreetsUserCanceled();
                    }
                }).create();
        return dialog;
    }

    @Override
    public void onCancel(DialogInterface dialog) {
        super.onCancel(dialog);
        selectionListener.onStreetsUserCanceled();
    }
}

两种解决方案都不太好... 1. 如果你在嵌套的片段中工作,它将无法正常工作;2. 它会启动一个新的对话框,因此当内容发生变化时,你无法进行任何漂亮的过渡/动画。 - User

3
处理 DialogFragment 的返回行为的最佳方法是不要对其进行修改,让它保持原样,并在此过程中重新思考您当前的方法。如果我在应用程序中看到一个对话框并按下返回键,我期望将对话框从屏幕上弹出,而不是在对话框的页面之间导航(希望我没有误读您的问题)。
你能做到这一点吗?在你的 DialogFragment 中,你可以使用自定义 Dialog(我假设你只是使用 onCreateDialog() 回调来返回带有列表的 Dialog),覆盖 onKeyDown() 回调以处理按下返回键的事件:
public class CustomDialog extends Dialog {

    protected CustomDialog(Context context) {
        super(context);
    }

    @Override
    public boolean onKeyDown(int keyCode, KeyEvent event) {
        if (keyCode == KeyEvent.KEYCODE_BACK && event.getRepeatCount() == 0) {
            // the back key was pressed so do something?
            return true;
        }
        return super.onKeyDown(keyCode, event);
    }

}

我也研究了一下Google+应用程序如何在DialogFragment中显示ActionBar,以提供HomeAsUp,但我没有找到任何相关信息。
您可以始终使Activity看起来像一个对话框。

谢谢。我使用DialogFragment,因为在平板电脑版本中可能将其用作片段。目前,我正在DialogFragment顶部工作一个伪ActionBar。 - RobGThai

2
The best way is to override onBackPressed() in the dialog , you created in onCreateDialog().
@Override
public Dialog onCreateDialog(Bundle savedInstanceState) {
    return new Dialog(getActivity(), getTheme()){
        @Override
        public void onBackPressed() {
            //do your stuff
        }
    };
}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接