材料設計仕様 によると、キーボードが表示されると、BottomNavigationView
はその下に隠れます。ただし、Android:windowSoftInputMode="adjustResize"
アクティビティのマニフェストでBottomNavigationView
がキーボードの上に移動します。
キーボードが開いているときに画面の下部へのスクロールを有効にするには、adjustResize
を設定する必要があります。ただし、BottomNavigationView
を表示したくありません。これはできますか?
現在の外観:
レイアウトXML(実際にはFrameLayout
があり、EditText
がその中にあるEditText
があります):
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout
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">
<EditText
Android:layout_width="match_parent"
Android:layout_height="wrap_content"
Android:hint="Input"
Android:layout_gravity="center"
Android:layout_centerVertical="true"/>
<Android.support.design.widget.BottomNavigationView
Android:layout_width="match_parent"
Android:layout_height="wrap_content"
Android:layout_alignParentBottom="true"
app:itemBackground="@color/colorPrimary"
app:menu="@menu/menu_bottom_navigation"
app:itemIconTint="@Android:color/white"
app:itemTextColor="@Android:color/white"/>
</RelativeLayout>
これをマニフェストのアクティビティに追加します
Android:windowSoftInputMode="adjustPan"
以下のようなので
<activity Android:name=".feature.home.HomeActivity"
Android:windowSoftInputMode="adjustPan"/>
私はOPが述べたのとまったく同じ状況を経験しました。明らかに画面の下部にBottomNavigationView
があり、その上にScrollView
がありました。
アクティビティで
adjustPan
を実行すると、キーボードが表示されてもスクロールが機能しないときに、BottomNavigationView
が一番下に残ります。
adjustResize
を実行するとスクロールは機能しますが、BottomNavigationViewはキーボードの上にプッシュされます。
以下では、同じことに対する2つのアプローチが考えられます。
アプローチ1
キーボードの表示/非表示で表示/非表示を設定するだけです。同じための簡単な回避策です。次のアプローチで、キーボードの非表示/表示イベントのリスナーを取得できます。
面白くするために、何らかのアニメーションでBottomNavigationViewを表示/非表示にしてみてください。
アプローチ2
いくつかのより良い方法(マテリアルデザインの方法)は、CoordinatorLayout
とスクロール動作(CollapsingToolBar
を見たことがあるのと同じ)を使用することです。
以下はレイアウトファイルです
_<?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.AppBarLayout
Android:layout_width="match_parent"
Android:layout_height="wrap_content">
<Android.support.v7.widget.Toolbar
Android:id="@+id/toolbar"
Android:layout_width="match_parent"
Android:layout_height="?attr/actionBarSize"
Android:background="?attr/colorPrimary"
Android:elevation="4dp"
Android:theme="@style/ThemeOverlay.AppCompat.ActionBar"
app:popupTheme="@style/ThemeOverlay.AppCompat.Light"
app:title="@string/title"
app:titleTextColor="@Android:color/white" />
</Android.support.design.widget.AppBarLayout>
<Android.support.v4.widget.NestedScrollView
Android:id="@+id/nestedScrollView"
Android:layout_width="match_parent"
Android:layout_height="match_parent"
app:layout_behavior="@string/appbar_scrolling_view_behavior">
------ Your Contents --------
</Android.support.v4.widget.NestedScrollView>
<Android.support.design.widget.BottomNavigationView
Android:id="@+id/navigation"
Android:layout_width="match_parent"
Android:layout_height="wrap_content"
Android:layout_gravity="bottom"
Android:background="?android:attr/windowBackground"
app:layout_behavior="@string/hide_bottom_view_on_scroll_behavior"
app:menu="@menu/navigation" />
</Android.support.design.widget.CoordinatorLayout>
_
それで終わりです。BottomNavigationViewは、下や上などにスクロールすると表示/非表示になります。ただし、あるシナリオでは、キーボードが非表示の場合、コンテンツが小さすぎてスクロールできない場合、直面する可能性のある別の問題があります。
そして問題は、キーボードが開いて下にスクロールするとBottomNavigationViewが非表示になり、戻るボタンを押すとキーボードが非表示になりますが、BottomNavigationViewはまだ非表示のままになるということです。現在、コンテンツはスクロールできないため、スクロールしようとしても、BottomNavigationViewは表示されません。もう一度表示するには、キーボードを再び表示し、BottomNavigationViewが表示されたら上にスクロールして、戻るボタンを押します。
この方法でこの問題を解決しようとしましたが、
グローバルリスナーを追加して、キーボードが表示または非表示になっているかどうかを確認します。ここで使用したコードは(Kotlinにありますが、必要な場合は簡単にJavaバージョンに変換できます))
_private fun addKeyboardDetectListener(){
val topView = window.decorView.findViewById<View>(Android.R.id.content)
topView.viewTreeObserver.addOnGlobalLayoutListener {
val heightDifference = topView.rootView.height - topView.height
if(heightDifference > dpToPx(this, 200F)){
// keyboard shown
Log.d(TAG, "keyboard shown")
} else {
// keyboard hidden
Log.d(TAG, "keyboard hidden")
val behavior = (navigation.layoutParams as CoordinatorLayout.LayoutParams).behavior as HideBottomViewOnScrollBehavior
behavior.slideUp(navigation)
}
}
}
fun dpToPx(context: Context, valueInDp: Float) : Float{
val displayMetrics = context.resources.displayMetrics
return TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, valueInDp, displayMetrics)
}
_
最後に、サポートライブラリバージョン28.0.0を使用すると、behavior.slideUp(navigation)
メソッドが保護されていることがわかります。したがって、アクティビティなどから呼び出すことはできません。
ただし、GoogleのAndroidチームはこれらのメソッドを新しい_material-components
_で既に公開しています。 チェックしてください 。
それとは別に、キーボードの非表示/表示などでプログラムでslideUpまたはslideDownを呼び出すなど、いくつかの実験を試すことができます。
追伸私はこの完全に機能するアプローチにかなりの時間を費やしてきたので、誰かの時間を節約できるように、ここで共有することを考えました。
マニフェストに次の行を追加します:Android:windowSoftInputMode = "adjustPan"
<activity
Android:name=".main.MainActivity"
Android:screenOrientation="portrait"
Android:windowSoftInputMode="adjustPan" />
adjustSpan
を必要としない別のソリューションがありますが、API >= 21
に対してのみ機能します。システムのインセットを追跡することにより、キーボードが表示/非表示になっているかどうかを検出できます。 BottomNavigationView
の子であるLinearLayout
があり、キーボードが表示されたら非表示にする必要があるとします。
> LinearLayout
> ContentView
> BottomNavigationView
必要なのは、LinearLayout
を次のように拡張することだけです。
public class KeyboardAwareLinearLayout extends LinearLayout {
public KeyboardAwareLinearLayout(Context context) {
super(context);
}
public KeyboardAwareLinearLayout(Context context, @Nullable AttributeSet attrs) {
super(context, attrs);
}
public KeyboardAwareLinearLayout(Context context,
@Nullable AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
}
public KeyboardAwareLinearLayout(Context context, AttributeSet attrs,
int defStyleAttr, int defStyleRes) {
super(context, attrs, defStyleAttr, defStyleRes);
}
@Override
public WindowInsets onApplyWindowInsets(WindowInsets insets) {
int childCount = getChildCount();
for (int index = 0; index < childCount; index++) {
View view = getChildAt(index);
if (view instanceof BottomNavigationView) {
int bottom = insets.getSystemWindowInsetBottom();
if (bottom >= ViewUtils.dpToPx(200)) {
view.setVisibility(GONE);
} else {
view.setVisibility(VISIBLE);
}
}
}
return insets;
}
}
アイデアは、キーボードが表示されると、システムインセットがかなり大きな.bottom
値で変更されるということです。