I'm trying to show a BottomSheetDialogFragment
with a few EditText
fields for the user to enter information. I want to show it directly above the keyboard, but it keeps covering up the contents.
This is what happens when I bring up the BottomSheetDialogFragment
, you can see it's selecting Card Number
EditText
, but covering the other content.
Ideally, this is what I'm looking for, you can see both EditTexts
, and the padding of the View.
I've tried a lot of solutions revolving around windowSoftInputMode
, but nothing seems to work. I've set it to adjustResize
for the parent Activity
and the actual BottomSheetDialogFragment
via
dialog.window.setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_ADJUST_RESIZE)
And I've also tried modifying my layout, changing it from a FrameLayout
, to a ScrollView
to a CoordinatorLayout
to see if that had any effect on the position of the layout, but nothing seems to work.
If anyone knows how to accomplish this, that would be greatly appreciated, thank you.
This following step might be helpful to resolve your problems.
First add the following line on your EditText in xml file
android:imeOptions="actionSend|flagNoEnterAction"
For example:
<EditText
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:inputType="number"
android:hint="Card number"
android:imeOptions="actionSend|flagNoEnterAction"/>
Then add the following line on activity tag in AndroidManifest.xml file
android:windowSoftInputMode="stateVisible|adjustResize"
For example:
<activity android:name=".stack.MainActivity"
android:windowSoftInputMode="stateVisible|adjustResize">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
you can finds more details about On-Screen input method from here.
Adding padding to the virtual keyboard is not supported by the Android OS itself, but there are hacky ways to have it.
One way would be to listen to the edittext's focus, and scroll the ScrollView a bit more like so:
edittext.setOnFocusChangeListener(new OnFocusChangeListener() {
@Override
public void onFocusChange(View v, boolean hasFocus) {
if (hasFocus)
scrollView.scrollBy(0, 100);
});
As I said, this way is hacky and not recommended.
Another way (which depends on your layout and Is better if you get it working) would be to set windowSoftInputMode
to adjustPan
or adjustResize
(depending on your layout) for your activity in AndroidManifest.xml.
Try this BottomSheetDialogFragment:
import android.graphics.Rect;
import android.os.Bundle;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
import android.support.design.widget.BottomSheetBehavior;
import android.support.design.widget.BottomSheetDialog;
import android.support.design.widget.BottomSheetDialogFragment;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.view.WindowManager;
public class TestBottomSheetDialog extends BottomSheetDialogFragment {
@Nullable
@Override
public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
View fragmentView = LayoutInflater.from(getContext()).inflate(R.layout.fragment_bottom_sheet, container, false);
if (getDialog().getWindow() != null) {
getDialog().getWindow().setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_ADJUST_RESIZE);
}
if (getActivity() != null) {
View decorView = getActivity().getWindow().getDecorView();
decorView.getViewTreeObserver().addOnGlobalLayoutListener(() -> {
Rect displayFrame = new Rect();
decorView.getWindowVisibleDisplayFrame(displayFrame);
int height = decorView.getContext().getResources().getDisplayMetrics().heightPixels;
int heightDifference = height - displayFrame.bottom;
if (heightDifference != 0) {
if (fragmentView.getPaddingBottom() != heightDifference) {
fragmentView.setPadding(0, 0, 0, heightDifference);
}
} else {
if (fragmentView.getPaddingBottom() != 0) {
fragmentView.setPadding(0, 0, 0, 0);
}
}
});
}
getDialog().setOnShowListener(dialog -> {
BottomSheetDialog d = (BottomSheetDialog) dialog;
View bottomSheetInternal = d.findViewById(android.support.design.R.id.design_bottom_sheet);
if (bottomSheetInternal == null) return;
BottomSheetBehavior.from(bottomSheetInternal).setState(BottomSheetBehavior.STATE_EXPANDED);
});
return fragmentView;
}
}
I had to enlarge a layout height. A programmatical method from How to change the default height of bottomsheet dialog fragment? didn't help, so I simply changed the layout.
<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"
>
<View
android:id="@+id/top_space"
android:layout_width="match_parent"
android:layout_height="10dp"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
/>
<!-- Other views -->
<View
android:id="@+id/bottom_space"
android:layout_width="match_parent"
android:layout_height="0dp"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/button"
app:layout_constraintVertical_weight="1"
/>
</android.support.constraint.ConstraintLayout>
I finally changed the height of dialog when keyboard is open and resized it to normal when it closes.
KeyboardVisibilityEvent library: https://android-arsenal.com/details/1/2519
KeyboardVisibilityEvent.setEventListener(activity) { isOpen ->
setDialogHeight(isOpen)
}
Support min SDK version is 14 for 2.0.0
And set dialog height to 80% when the keyboard opens:
/**
* Changes size of dialog based on keyboard visibility state
*/
private fun setDialogHeight(expanded: Boolean) {
val dialog = dialog as BottomSheetDialog?
val bottomSheet =
dialog!!.findViewById<View>(com.google.android.material.R.id.design_bottom_sheet) as FrameLayout?
val behavior = BottomSheetBehavior.from(bottomSheet!!)
val displayMetrics = activity!!.resources.displayMetrics
val width = displayMetrics.widthPixels
val height = displayMetrics.heightPixels
val maxHeight = (height * 0.88).toInt()
behavior.peekHeight = if (expanded) maxHeight else -1
}
Maybe a late answer but would probably help.
Nothing else worked for me. But this solution is working
Wrap layout inside NestedScrollView
<androidx.core.widget.NestedScrollView
android:layout_width="match_parent"
android:layout_height="wrap_content">
<--Rest of the layout-->
</androidx.core.widget.NestedScrollView>
Inside styles:
<style name="BottomSheetDialogTheme" parent="Theme.Design.Light.BottomSheetDialog">
<item name="bottomSheetStyle">@style/AppModalStyle</item>
<item name="android:windowIsFloating">false</item>
<item name="android:windowSoftInputMode">adjustResize</item>
</style>
<style name="AppModalStyle" parent="Widget.Design.BottomSheet.Modal">
<item name="android:background">@drawable/rounded_corner_dialog</item>
</style>
Here android:windowIsFloating
should be false & android:windowSoftInputMode
must be adjustResize
来源:https://stackoverflow.com/questions/50223392/android-show-bottomsheetdialogfragment-above-keyboard