5

I'm trying to add a dialog to my android app which is full screen on small devices (e.g. mobile phone) but a standard dialog on large devices (e.g. tablets). This follows the logic laid out in the material design specification.

Using the official android dialog guide, using a DialogFragment, I end up with a transparent dialog that overlays the action bar:

enter image description here

Below is the source code.

main.xml

<?xml version="1.0" encoding="utf-8"?>
<android.support.design.widget.CoordinatorLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    android:layout_width="match_parent"
    android:layout_height="match_parent">

    <android.support.design.widget.CoordinatorLayout
        android:id="@+id/toolbar_layout"
        android:layout_width="match_parent"
        android:layout_height="wrap_content">

        <!-- Use ThemeOverlay to make the toolbar text white -->
        <android.support.design.widget.AppBarLayout
            android:id="@+id/abl_top"
            android:layout_height="wrap_content"
            android:layout_width="match_parent"
            android:theme="@style/ThemeOverlay.AppCompat.Dark.ActionBar">

            <android.support.v7.widget.Toolbar
                android:id="@+id/toolbar"
                android:fitsSystemWindows="true"
                android:layout_height="wrap_content"
                android:layout_width="match_parent"
                app:popupTheme="@style/ThemeOverlay.AppCompat.Light"
                app:layout_scrollFlags="scroll|enterAlways"/>

        </android.support.design.widget.AppBarLayout>
    </android.support.design.widget.CoordinatorLayout>

    <FrameLayout
        android:id="@+id/content"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"/>

    <android.support.design.widget.FloatingActionButton
        android:id="@+id/fab"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_gravity="end|bottom"
        android:layout_margin="10dp"
        android:src="@drawable/ic_add"
        android:clickable="true"/>

</android.support.design.widget.CoordinatorLayout>

MainActivity.java

package com.example.fsdialog;

import android.os.Bundle;
import android.support.design.widget.FloatingActionButton;
import android.support.v4.app.FragmentManager;
import android.support.v4.app.FragmentTransaction;
import android.support.v7.app.AppCompatActivity;
import android.support.v7.app.ActionBar;
import android.support.v7.widget.Toolbar;
import android.view.View;

public class MainActivity extends AppCompatActivity
{

    /** Called when the activity is first created. */
    @Override
    public void onCreate(Bundle savedInstanceState)
    {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);

        // Setup AppBar
        Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);
        if (toolbar != null) {
            setSupportActionBar(toolbar);
        }

        final ActionBar ab = getSupportActionBar();
        ab.setHomeAsUpIndicator(R.drawable.ic_menu);
        ab.setDisplayHomeAsUpEnabled(true);

        // FAB
        FloatingActionButton fab = (FloatingActionButton) findViewById(
                R.id.fab);
        fab.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                FragmentManager fm = getSupportFragmentManager();
                MyDialogFragment dialog = new MyDialogFragment();

                if (false) {
                    // The device is using a large layout, so show the fragment
                    // as a dialog
                    dialog.show(fm, "MyDialogFragment");
                } else {
                    // The device is smaller, so show the fragment fullscreen
                    FragmentTransaction tx = fm.beginTransaction();
                    tx.setTransition(FragmentTransaction.TRANSIT_FRAGMENT_OPEN);

                    // To make it fullscreen, use the 'content' root view as
                    // the container for the fragment, which is always the root
                    // view for the activity
                    tx.add(R.id.content, dialog)
                      .addToBackStack(null).commit();
                }

            }
        });
    }

}

my_dialog.xml

<?xml version="1.0" encoding="utf-8"?>
<GridLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:rowCount="2"
    android:columnCount="2">

    <TextView
        android:id="@+id/text_date1"
        android:layout_row="0"
        android:layout_column="0"
        android:text="17/06/2015"
        style="@android:style/Widget.Holo.Spinner"/>
    <TextView
        android:id="@+id/text_time1"
        android:layout_row="0"
        android:layout_column="1"
        android:text="09:35"
        style="@android:style/Widget.Holo.Spinner"/>
    <TextView
        android:id="@+id/text_date2"
        android:layout_row="1"
        android:layout_column="0"
        android:text="17/06/2015"
        style="@android:style/Widget.Holo.Spinner"/>
    <TextView
        android:id="@+id/text_time2"
        android:layout_row="1"
        android:layout_column="1"
        android:text="11:00"
        style="@android:style/Widget.Holo.Spinner"/>

</GridLayout>

MyDialogFragment.java

package com.example.fsdialog;

import android.app.Dialog;
import android.os.Bundle;
import android.support.v4.app.DialogFragment;
import android.view.View;
import android.view.ViewGroup;
import android.view.LayoutInflater;
import android.view.Window;

public class MyDialogFragment
    extends DialogFragment
{
    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container,
                             Bundle savedInstanceState) {
        return inflater.inflate(R.layout.my_dialog, container, false);
    }

    @Override
    public Dialog onCreateDialog(Bundle savedInstanceState) {
        Dialog dialog = super.onCreateDialog(savedInstanceState);
        dialog.requestWindowFeature(Window.FEATURE_NO_TITLE);
        return dialog;
    }
}

AndroidManifest.xml

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
      package="com.example.fsdialog"
      android:versionCode="1"
      android:versionName="1.0">
    <application android:label="@string/app_name"
                 android:icon="@drawable/ic_launcher">
        <activity android:name="MainActivity"
                  android:label="@string/app_name"
                  android:theme="@style/Theme.AppCompat.NoActionBar">
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />
                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>
    </application>
</manifest>

UPDATE 1 (24-06-2015)

I'm now using the android Theme.AppCompat.NoActionBar theme and have a FrameLayout in the main activity. I still get the same problem (image updated).

  • Is it wrong for me to assume that the built in theme will contain a background colour for the dialog? You know, a sane default? I know for sure that if I just show a dialog the normal way it gets a background colour.
  • I assume the CoordinatorLayout I added causes the dialog to overlay the action bar even though I'm using an embedded FrameLayout. Why is that? I need the CoordinatorLayout so the FloatingActionButton is in the correct position.
Jon
  • 9,815
  • 9
  • 46
  • 67
  • Easiest solution is to set the background property of your DialogFragment layout (`my_dialog.xml`) to whatever you want it to be. The correct way of doing it is to look at the theme you're using and setting the correct attributes on the theme for your desired behavior/style (I don't know what these are off the top of my head). – kha Jun 24 '15 at 07:56
  • You're adding dialogfragment to root layout (activity layout)... that's why it is positioned where it is. Use some FrameLayout inside root layout and position it where you want to have your dialog on tablets (ie. centerinparent of relativelayout). You don't have any background set for your dialog layout. Dialog is transparent because of that. – vaske Jun 24 '15 at 07:57
  • I've updated my question to include new code with a FrameLayout and use of a built in theme. The problem remains. – Jon Jun 24 '15 at 09:50

1 Answers1

1

@cutoff was correct. My update failed because the root layout is a CoordinatorLayout instead of a LinearLayout or something equally good. The example below uses a DrawerLayout:

<?xml version="1.0" encoding="utf-8"?>
<android.support.v4.widget.DrawerLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    android:id="@+id/drawer_layout"
    android:layout_height="match_parent"
    android:layout_width="match_parent"
    android:fitsSystemWindows="true">

    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:orientation="vertical">

        <android.support.design.widget.CoordinatorLayout
            android:id="@+id/toolbar_layout"
            android:layout_width="match_parent"
            android:layout_height="wrap_content">

            <!-- Use ThemeOverlay to make the toolbar and tablayout text
                 white -->
            <android.support.design.widget.AppBarLayout
                android:id="@+id/abl_top"
                android:layout_height="wrap_content"
                android:layout_width="match_parent"
                android:theme="@style/ThemeOverlay.AppCompat.Dark.ActionBar">

                <android.support.v7.widget.Toolbar
                    android:id="@+id/toolbar"
                    android:fitsSystemWindows="true"
                    android:layout_height="wrap_content"
                    android:layout_width="match_parent"
                    app:popupTheme="@style/ThemeOverlay.AppCompat.Light"
                    app:layout_scrollFlags="scroll|enterAlways"/>

            </android.support.design.widget.AppBarLayout>
        </android.support.design.widget.CoordinatorLayout>

        <FrameLayout
            android:id="@+id/content"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"/>

    </LinearLayout>

    <android.support.design.widget.NavigationView
        android:id="@+id/nav_view"
        android:layout_height="match_parent"
        android:layout_width="wrap_content"
        android:layout_gravity="start"
        android:fitsSystemWindows="true"
        app:headerLayout="@layout/nav_header"
        app:menu="@menu/nav_view"/>

</android.support.v4.widget.DrawerLayout>

More details about this solution can be found in this question, including why a DialogFragment is insufficient for anything other than completely full-screen.

Community
  • 1
  • 1
Jon
  • 9,815
  • 9
  • 46
  • 67