I have been googling and searching Stack Overflow 2 days, but haven't found something that could help me.
I'm trying to implement a DialogFragment that's fullscreen on smartphones and a modal dialog on tablets.
This is how it is supposed to look (taken on an API level 23 device):
This is how it looks on an API level 24 device:
This works with the following code on devices with API level <= 23 I tested it on multiple real and emulated devices.
TestDialogFragment.java:
public class TestDialogFragment extends DialogFragment
{
private boolean isTablet;
public TestDialogFragment()
{
}
@Override
public void onCreate(@Nullable Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
isTablet = getResources().getBoolean(R.bool.isTablet); // defaults to false, true >= sw600dp
if (isTablet)
{
setStyle(DialogFragment.STYLE_NO_TITLE, android.R.style.Theme_Holo_Light_Dialog_NoActionBar_MinWidth);
} else
{
setStyle(STYLE_NO_FRAME, android.R.style.Theme_Holo_Light);
}
setCancelable(false);
}
@Nullable
@Override
public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle
savedInstanceState)
{
if (!isTablet)
{
Window window = getDialog().getWindow();
if (window != null)
{
window.setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_ADJUST_RESIZE);
}
}
return inflater.inflate(R.layout.dialog_fragment, container, false);
}
@Override
public void onStart()
{
super.onStart();
if (isTablet)
{
Dialog d = getDialog();
if (d != null)
{
int width = ViewGroup.LayoutParams.WRAP_CONTENT;
int height = ViewGroup.LayoutParams.MATCH_PARENT;
d.getWindow().setLayout(width, height);
}
}
}
}
dialog_fragment.xml:
<android.support.constraint.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent">
<android.support.v7.widget.Toolbar
android:id="@+id/dialog_toolbar"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:background="@color/colorPrimary"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toTopOf="parent">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginRight="8dp"
android:ellipsize="end"
android:fontFamily="sans-serif-medium"
android:maxLines="2"
android:paddingBottom="14dp"
android:paddingTop="14dp"
android:text="@string/dialog_title"
android:textSize="20sp" />
</android.support.v7.widget.Toolbar>
<EditText
android:id="@+id/edit_text"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginLeft="4dp"
android:layout_marginRight="4dp"
android:ems="10"
android:hint="@string/edit_text_1"
android:inputType="text"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toLeftOf="@+id/progress_bar"
app:layout_constraintTop_toBottomOf="@+id/dialog_toolbar"
app:theme="@style/AppTheme" />
<ProgressBar
android:id="@+id/progress_bar"
style="?android:progressBarStyle"
android:layout_width="24dp"
android:layout_height="0dp"
android:layout_marginLeft="4dp"
android:layout_marginRight="4dp"
android:visibility="invisible"
app:layout_constraintBottom_toBottomOf="@id/edit_text"
app:layout_constraintHorizontal_bias="1.0"
app:layout_constraintLeft_toRightOf="@id/edit_text"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toTopOf="@id/edit_text"
app:layout_constraintWidth_default="wrap"
tools:visibility="visible" />
<android.support.v7.widget.RecyclerView
android:id="@+id/results_recycler_view"
android:layout_width="0dp"
android:layout_height="0dp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toBottomOf="@+id/edit_text"/>
<TextView
android:id="@+id/no_results_text_view"
android:layout_width="0dp"
android:layout_height="0dp"
android:layout_marginTop="32dp"
android:gravity="center"
android:text="@string/no_results"
android:visibility="gone"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toBottomOf="@id/edit_text"
app:layout_constraintVertical_bias="0.0"
app:layout_constraintHeight_default="wrap"
tools:visibility="visible" />
</android.support.constraint.ConstraintLayout>
I can't figure out why this doesn't also work on API level 24 and up. I see no changes to this behaviour in the release notes for Android 24.
Is there anything wrong with my code or have I overlooked anything?
Thanks in advance for your help!
I managed to at least get the contents of the dialog to be always visible by expanding this class from Mike Penz's MaterialDrawer library. This isn't the prettiest solution, but atleast everything in the dialog can be interacted with with the keyboard open.
Here is the code:
public class KeyboardUtil
{
private View activityDecorView;
private View dialogDecorView;
private View contentView;
private int diff;
//a small helper to allow showing the editText focus
ViewTreeObserver.OnGlobalLayoutListener activityListener = new ViewTreeObserver.OnGlobalLayoutListener()
{
@Override
public void onGlobalLayout()
{
Rect r = new Rect();
//r will be populated with the coordinates of your view that area still visible.
activityDecorView.getWindowVisibleDisplayFrame(r);
//get screen height and calculate the difference with the usable area from r
int height = activityDecorView.getContext().getResources().getDisplayMetrics().heightPixels;
diff = height - r.bottom;
//no difference means no keyboard, so remove padding
if (diff == 0)
{
//check if the padding is != 0 (if yes reset the padding)
if (contentView.getPaddingBottom() != 0)
{
//reset the padding of the contentView
contentView.setPadding(0, 0, 0, 0);
}
}
}
};
ViewTreeObserver.OnGlobalLayoutListener dialogListener = new ViewTreeObserver.OnGlobalLayoutListener()
{
@Override
public void onGlobalLayout()
{
//if it could be a keyboard and the view hasn't shrunk on it's own add the padding to the view
if (diff != 0 && activityDecorView.getContext().getResources().getDisplayMetrics().heightPixels - diff >
contentView.getHeight())
{
//the view shrunk on it's own. remove padding
//check if the padding is != 0 (if yes reset the padding)
if (contentView.getPaddingBottom() != 0)
{
//reset the padding of the contentView
contentView.setPadding(0, 0, 0, 0);
}
} else
{
// if the usable screen height differs from the total screen height we assume that it shows a
// keyboard now
//check if the padding is 0 (if yes set the padding for the keyboard)
if (contentView.getPaddingBottom() != diff)
{
//set the padding of the contentView for the keyboard
contentView.setPadding(0, 0, 0, diff);
}
}
}
};
public KeyboardUtil(Activity act, View contentView)
{
this.activityDecorView = act.getWindow().getDecorView();
this.contentView = contentView;
//only required on newer android versions. it was working on API level 19
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT)
{
activityDecorView.getViewTreeObserver().addOnGlobalLayoutListener(activityListener);
}
}
public KeyboardUtil(Activity act, Dialog dialog, View contentView)
{
this(act, contentView);
if (dialog.getWindow() != null)
{
this.dialogDecorView = dialog.getWindow().getDecorView();
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT)
{
dialogDecorView.getViewTreeObserver().addOnGlobalLayoutListener(dialogListener);
}
}
}
public void enable()
{
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT)
{
activityDecorView.getViewTreeObserver().addOnGlobalLayoutListener(activityListener);
if (dialogDecorView != null)
{
dialogDecorView.getViewTreeObserver().addOnGlobalLayoutListener(dialogListener);
}
}
}
public void disable()
{
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT)
{
activityDecorView.getViewTreeObserver().removeOnGlobalLayoutListener(activityListener);
if (dialogDecorView != null)
{
dialogDecorView.getViewTreeObserver().removeOnGlobalLayoutListener(dialogListener);
}
}
}
/**
* Helper to hide the keyboard
*
* @param act
*/
public static void hideKeyboard(Activity act)
{
if (act != null && act.getCurrentFocus() != null)
{
InputMethodManager inputMethodManager = (InputMethodManager) act.getSystemService(Activity
.INPUT_METHOD_SERVICE);
inputMethodManager.hideSoftInputFromWindow(act.getCurrentFocus().getWindowToken(), 0);
}
}
}