Selon le Material Design Spec , lorsque le clavier apparaît, le BottomNavigationView
devrait se cacher en dessous. Cependant, si je mets Android:windowSoftInputMode="adjustResize"
dans le manifeste de l'activité, puis le BottomNavigationView
se déplace au-dessus du clavier.
Je dois définir adjustResize
pour activer le défilement vers le bas de l'écran lorsque le clavier est ouvert. Cependant, je ne veux pas que le BottomNavigationView
soit visible. Cela peut-il être fait?
À quoi il ressemble actuellement:
La mise en page XML (en réalité, il y aurait un FrameLayout
où se trouve le EditText
et le EditText
à l'intérieur):
<?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>
Ajoutez ceci à votre activité dans le manifeste
Android:windowSoftInputMode="adjustPan"
Alors comme
<activity Android:name=".feature.home.HomeActivity"
Android:windowSoftInputMode="adjustPan"/>
J'ai vécu exactement la même situation que OP a déclaré, j'avais un BottomNavigationView
évidemment au bas de l'écran et au-dessus il y avait ScrollView
.
Maintenant, si nous faisons
adjustPan
en activité, alorsBottomNavigationView
reste en bas lorsque le clavier apparaît mais le défilement ne fonctionne pas.Et si nous faisons
adjustResize
alors le défilement fonctionne mais BottomNavigationView est poussé au-dessus du clavier.
Je pense que ci-dessous peut être deux approches pour le même.
Approche 1
Réglez simplement la visibilité sur disparu/visible lors de l'affichage/masquage du clavier. C'est un travail rapide pour la même chose. Vous pouvez obtenir un écouteur pour l'événement de masquage/affichage du clavier dans la prochaine approche.
Pour le rendre intéressant, vous pouvez essayer d'afficher/masquer BottomNavigationView avec une sorte d'animation.
Approche 2
Une meilleure façon (la méthode de conception matérielle) serait d'utiliser CoordinatorLayout
et le comportement de défilement (comme vous avez pu le voir CollapsingToolBar
).
Ci-dessous serait le fichier de mise en page
<?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>
Ça y est, vous pouvez maintenant voir le BottomNavigationView se cacher/s'afficher lors du défilement vers le bas et le haut, etc.
Et le problème est que lorsque le clavier s'ouvre et que vous faites défiler vers le bas, ce qui masque le BottomNavigationView, maintenant si vous appuyez sur le bouton de retour, le clavier se cache mais le BottomNavigationView reste toujours masqué. Maintenant, comme le contenu ne peut pas défiler, donc si vous essayez de faire défiler, il n'affiche pas BottomNavigationView. Pour le révéler à nouveau, vous devez à nouveau rendre le clavier visible et faire défiler vers le haut, lorsque BottomNavigationView s'affiche, puis appuyez sur le bouton de retour.
J'ai essayé de résoudre ce problème de cette façon,
Ajoutez un écouteur global pour savoir si le clavier est affiché ou masqué. Le code que j'ai utilisé ici était (il est dans Kotlin, mais vous pouvez facilement le convertir en Java si vous en avez besoin))
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)
}
Et la dernière chose, si vous utilisez la bibliothèque de support version 28.0.0, vous verrez que la méthode behavior.slideUp(navigation)
est protégée, vous ne pouvez donc pas l'appeler depuis votre activité, etc.
Cependant, Google Android a déjà rendu ces méthodes publiques dans le nouveau material-components
. Cochez ceci il vous suffit donc d'importer des composants matériels dans votre projet et d'utiliser cette classe au lieu.
En dehors de cela, vous pouvez essayer d'autres expériences comme appeler par programmation slideUp ou slideDown sur le clavier masquer/afficher, etc.
P.S. J'ai passé beaucoup de temps à arriver à cette approche pleinement fonctionnelle, alors j'ai pensé à la partager ici, afin qu'elle puisse faire gagner du temps à quelqu'un.
ajoutez la ligne suivante dans votre manifeste: Android: windowSoftInputMode = "adjustPan"
<activity
Android:name=".main.MainActivity"
Android:screenOrientation="portrait"
Android:windowSoftInputMode="adjustPan" />
Il existe une autre solution, qui ne nécessite pas adjustSpan
, mais elle ne fonctionne que pour API >= 21
. Vous pouvez détecter si le clavier est affiché/masqué en suivant les encarts du système. Supposons que vous ayez BottomNavigationView
, qui est l'enfant de LinearLayout
et que vous devez le masquer lorsque le clavier est affiché:
> LinearLayout
> ContentView
> BottomNavigationView
Tout ce que vous devez faire est d'étendre LinearLayout
de la manière suivante:
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;
}
}
L'idée est que lorsque le clavier est affiché, les insertions système sont modifiées avec un assez gros .bottom
valeur.