How to display an existing ListFragment in a Dialo

2019-01-23 16:50发布

问题:

I have the following problem:

I have an exisiting ListFragment, but I would like to display this as a dialog.

My first approach was to create a DialogFragment which has to ListFragment inside of it, but appearently it is currently not possible to put fragments in fragments.

Extending DialogFragment instead of ListFragment is also not possible, because of the heavy use of ListFragment methods.

Is there an easy way to do this?

回答1:

What works for me is

1) in xml layout for your DialogFragment called, let's say, DialogFragmentwWithListFragment specify ListFragment class
E.g. dialog_fragment_with_list_fragment.xml :

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
        android:layout_width="match_parent"
        android:layout_height="match_parent">
        <fragment
             android:id="@+id/flContent"
             android:layout_width="match_parent"
             android:layout_height="match_parent"
             android:padding = "10dp"
             class="com.xxx.yyy.DialogFragmentwWithListFragment " />
</LinearLayout>

2) in DialogFragmentwWithListFragment inflate dialog_fragment_with_list_fragment.xml

@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
    return inflater.inflate(R.layout.dialog_fragment_with_list_fragment, null);
}

3) invoke DialogFragmentwWithListFragment as regular DialogFragment:

 DialogFragmentwWithListFragment dialogFragment = DialogFragmentwWithListFragment  .newInstance();
 dialogFragment.setRetainInstance(true);
 dialogFragment.show(getFragmentManager(), "tag");


Hope, it helps.



回答2:

I would either put the ListView inside a DialogFragment or try to put the ListFragment inside a Dialog. I am not sure if the second one is possible though.



回答3:

You can show a list through a DialogFragment this way:(using the support v4 library)

public class MyListDialogFragment extends DialogFragment {
    onDlgListClick mCallback;

    private String[] lista;//the list you want to show with the dialog

    public static MyListDialogFragment newInstance(Bundle fB){
    MyListDialogFragment lstFrag = new MyListDialogFragment();
    Bundle args = new Bundle();
        args.putStringArray("lista", fB.getStringArray("lista"));//the list
        args.putString("titulo", fB.getString("titulo"));//the title of the list
        lstFrag.setArguments(args);

        return lstFrag;
    }

    public interface onDlgListClick{
        public void onLstItemSelected(String selection);
    }

    @Override
    public void onAttach(Activity activity) {
        super.onAttach(activity);

        // This makes sure that the container activity has implemented
        // the callback interface. If not, it throws an exception
        try {
            mCallback = (onDlgListClick) activity;
        } catch (ClassCastException e) {
            throw new ClassCastException(activity.toString()
                    + " must implement onLstItemSelected");
        }
        this.setCancelable(false);
    }

     @Override
     public Dialog onCreateDialog(Bundle savedInstanceState) {
         lista = getArguments().getStringArray("lista");

         return new AlertDialog.Builder(getActivity())
         .setTitle(getArguments().getString("titulo"))
         .setCancelable(false)
         .setItems(lista, new DialogInterface.OnClickListener(){
            public void onClick(DialogInterface dialog, int item){

                mCallback.onLstItemSelected(lista[item]);
                getDialog().dismiss(); //maybe you dont need these two lines
                MyListDialogFragment.this.dismiss();
            }
         }).create();
     }

}

On the main activity you extend FragmentActivity and implements the interface MyListDialogFragment.onDlgListClick

//the interface
@Override
public void onLstItemSelected(String selection) {//list dialog fragment interface
//do whatever you want
}

//calling the dialog
public void showFrags(int id){

        Bundle fB = new Bundle();

        FragmentTransaction ft = getSupportFragmentManager().beginTransaction();
        Fragment prev = getSupportFragmentManager().findFragmentByTag("listdialog");
        if (prev != null) {
            ft.remove(prev);
        }
        ft.commit();
        switch(id){
        case 0:
        fB.putStringArray("lista", list); fB.putString("titulo",title);
        MyListDialogFragment newListDlg = MyListDialogFragment.newInstance(fB);
        newListDlg.show(ft, "listdialog");
        break;
        }
}


回答4:

When adding a fragment inside another fragment, the documentation says you should do it dynamically (i.e., rather than hardcoding a <fragment> tag into your layout XML.

So here is how to do it dynamically. In this case, I add MyListFragment to MyDialogFragment:

MyDialogFragment.java

import android.app.Dialog;
import android.content.Intent;
import android.os.Bundle;
import android.support.annotation.Nullable;
import android.support.v4.app.DialogFragment;
import android.support.v4.app.FragmentManager;
import android.support.v4.app.FragmentTransaction;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.Button;
import android.widget.EditText;

public class MyDialogFragment extends DialogFragment {

    public static final String TAG = MyDialogFragment.class.getSimpleName();
    private static final String ARG_TITLE = "ARG_TITLE";

    private EditText mEditText;

    public MyDialogFragment() {
        // Empty constructor required for DialogFragment
    }

    public static MyDialogFragment newInstance(String title) {
        MyDialogFragment myDialogFragment = new MyDialogFragment();
        Bundle args = new Bundle();
        args.putString(ARG_TITLE, title);
        myDialogFragment.setArguments(args);
        return myDialogFragment;
    }

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
    }


    @Override
    public Dialog onCreateDialog(Bundle savedInstanceState) {
        Dialog dialog = super.onCreateDialog(savedInstanceState);
        Bundle args = getArguments();
        if (args != null) {
            dialog.setTitle(args.getString(ARG_TITLE));
        }
        return dialog;
    }

    public void setTitle(String title) {
        Dialog dialog = getDialog();
        dialog.setTitle(title);
    }

    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container,
                             Bundle savedInstanceState) {
        View view = inflater.inflate(R.layout.dialog_fragment_selected_products, container, false);
        //addInnerFragment();

        Button okButton = (Button)view.findViewById(R.id.okButton);
        okButton.setOnClickListener(
                new View.OnClickListener() {
                    @Override
                    public void onClick(View view) {
                        dismiss();
                        //dismissAllowingStateLoss();
                    }
                }
        );

        return view;
    }

    @Override
    public void onStart() {
        super.onStart();
        //addInnerFragment();
    }

    @Override
    public void onViewCreated(View view, @Nullable Bundle savedInstanceState) {
        super.onViewCreated(view, savedInstanceState);
        addInnerFragment();
    }

    public void addInnerFragment() {

        FragmentManager childFragmentManager = getChildFragmentManager();
        FragmentTransaction transaction = childFragmentManager.beginTransaction();
        //transaction.add(R.id.fragmentContainer, new MyListFragment());
        transaction.add(R.id.fragmentContainer, MyListFragment.newInstance(MyListFragment.MODE_SELL));
        //transaction.commit();
        transaction.commitAllowingStateLoss();
        childFragmentManager.executePendingTransactions();

    }

}

(As you will see, it also contains some functionality to set the title of the dialog.)

dialog_fragment_selected_products.xml

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:paddingBottom="@dimen/activity_vertical_margin"
    android:paddingLeft="@dimen/activity_horizontal_margin"
    android:paddingRight="@dimen/activity_horizontal_margin"
    android:paddingTop="@dimen/activity_vertical_margin"
    tools:context=".MyDialogFragment"
    android:orientation="vertical">

    <LinearLayout
        android:id="@+id/fragmentContainer"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:orientation="vertical"
        android:layout_alignParentTop="true"
        android:layout_above="@+id/okButton" />

    <Button
        android:id="@+id/okButton"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_alignParentBottom="true"
        android:text="@string/ok" />

</RelativeLayout>

Another advantage of doing it this way is that you can create an instance of the inner fragment in order to pass any arguments to it.

For completeness, here is the code that I use in my activity to show the DialogFragment:

MyActivity.java

private void showCurrentItemsDialog() {

    MyDialogFragment myDialogFragment = MyDialogFragment.newInstance("cpuk.org");
    //myDialogFragment.setRetainInstance(true);

    FragmentManager fragmentManager = getSupportFragmentManager();
    FragmentTransaction transaction = fragmentManager.beginTransaction();
    transaction.add(myDialogFragment, MyDialogFragment.TAG);
    transaction.commitAllowingStateLoss();
    fragmentManager.executePendingTransactions();

}