Search code examples
androidandroid-fragmentsandroid-dialogfragmentmaster-detailandroid-actionbar-compat

Is it possible to display a DialogFragment in a master-detail arragement without a new activity?


I'm looking for a way to display a DialogFragment in single-pane mode without creating a new activity.

I originally set up a DialogFragment as a popup dialog in my Android app, with the intent to eventually pursue the master-detail pattern for larger devices.

However, now that I'm looking to finally implement the master-detail setup I'm running into all sorts of UI complications. Basically, I'd like to have something like a 'contextual action mode' update to the action bar. That requires some planning in two-pane mode, but it doesn't work at all with a popup dialog (unless I'm missing some way to show the action bar and the popup dialog).

I'd rather not create a new activity to house the detail DialogFragment on non-tablet/large devices, since there is a lot of DB-related code in the existing activity. However, I have trouble just doing FragmentTransaction.replace because the main view is based on a modified FragmentTabsPager from the compatibility lib v4 demo. I don't have a fragment to replace, unless I wrap the entire pager in a fragment - and I'm worried that nesting fragments is a hack that will complicate, rather simplify things in the long run. Am I wrong?

I'm also using ActionBarCompat, which complicates things as there are some UI options that aren't ported. I'd consider going API 11+ if it meant finding a clean solution to this.

BTW I'm starting to look at Commonsware's master-detail library, but it's a bit of code to grok and ingest, and I think it would require a few possibly big changes to make my code compatible.

Any suggestions or comments? I think I'm too close to this one to see how to simplify it...


Solution

  • Try this:

    This is the XML of the layout of your Activity. What you need to do is enclose all your activity content in a layout (like i have done here in id = all_activity_content_id).

    Now put two more views in the activity:- A RelativeLayout for your dialog and a View for making the background translucent.

    Note: Make sure the root layout of your activity is a RelativeLayout

    <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"
    tools:context="in.curium.testandroid.MainActivity" >
    
    <!-- all your activity's existing code goes here -->
    
    <RelativeLayout
        android:id="@+id/all_activity_content_id"
        android:layout_width="fill_parent"
        android:layout_height="fill_parent"
        android:background="@android:color/holo_red_light" >
    
        <ToggleButton
            android:id="@+id/toggle_dialog_box_id"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_centerVertical="true"
            android:padding="10dp"
            android:textOff="@string/show_dialog"
            android:textOn="@string/hide_dialog" />
    </RelativeLayout>
    
    <!-- translucent black background behind the dialog -->
    
    <View
        android:id="@+id/black_layer_id"
        android:layout_width="fill_parent"
        android:layout_height="fill_parent"
        android:alpha="0.6"
        android:background="@android:color/black"
        android:visibility="gone" />
    
    <!-- your dialog layout -->
    
    <RelativeLayout
        android:id="@+id/dialog_id"
        android:layout_width="200dp"
        android:layout_height="150dp"
        android:layout_alignParentRight="true"
        android:layout_centerVertical="true"
        android:layout_marginRight="10dp"
        android:background="#00BFFF"
        android:visibility="gone" >
    
        <TextView
            android:id="@+id/dialog_title_id"
            android:layout_width="fill_parent"
            android:layout_height="wrap_content"
            android:background="@android:color/black"
            android:text="@string/dialog_title"
            android:textColor="@android:color/white" />
    
        <TextView
            android:layout_width="fill_parent"
            android:layout_height="wrap_content"
            android:layout_below="@id/dialog_title_id"
            android:text="@string/dialog_description" />
    </RelativeLayout>
    

    In your activity class add two methods to show and hide the dialog layout. Override the back button to dismiss the dialog when visible otherwise call super.

    public class MainActivity extends Activity {
    
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
    
    
        ToggleButton toggleButton = (ToggleButton) findViewById(R.id.toggle_dialog_box_id);
        toggleButton.setOnClickListener(new OnClickListener() {
    
            @Override
            public void onClick(View toggleB) {
                boolean isOn = ((ToggleButton) toggleB).isChecked();
                if (isOn) {
                    showDialog();
                } else {
                    hideDialog();
                }
            }
        });
    }
    
    @Override
    public boolean onCreateOptionsMenu(Menu menu) {
        // Inflate the menu; this adds items to the action bar if it is present.
        getMenuInflater().inflate(R.menu.main, menu);
        return true;
    }
    
    @Override
    public boolean onOptionsItemSelected(MenuItem item) {
        // Handle action bar item clicks here. The action bar will
        // automatically handle clicks on the Home/Up button, so long
        // as you specify a parent activity in AndroidManifest.xml.
        int id = item.getItemId();
        if (id == R.id.action_settings) {
            return true;
        }
        return super.onOptionsItemSelected(item);
    }
    
    private void showDialog() {
        View opaqueBackground = findViewById(R.id.black_layer_id);
        RelativeLayout dialog = (RelativeLayout) findViewById(R.id.dialog_id);
        opaqueBackground.setVisibility(View.VISIBLE);
        dialog.setVisibility(View.VISIBLE);
    }
    
    private void hideDialog() {
        View opaqueBackground = findViewById(R.id.black_layer_id);
        RelativeLayout dialog = (RelativeLayout) findViewById(R.id.dialog_id);
        opaqueBackground.setVisibility(View.GONE);
        dialog.setVisibility(View.GONE);
    }
    
    @Override
    public void onBackPressed() {
        ToggleButton toggleB = (ToggleButton) findViewById(R.id.toggle_dialog_box_id);
        boolean isOn = toggleB.isChecked();
        if (isOn) {
            toggleB.setChecked(false);
            hideDialog();
        } else {
            super.onBackPressed();
        }
    }}
    

    Now any code that you want to put in the dialog will have access to the database adapter that you have in the activity.

    Positioning the dialog in the center of your detail fragment will be a bit tricky.

    Hope this helps.

    Source Code: https://github.com/testv200/DialogInsideAcitvity