How to hide the BottomNavigationView below keyboard with adjustResize set
Asked Answered
C

7

55

According to the material design spec, when the keyboard appears, the BottomNavigationView should hide underneath it. However, if I set android:windowSoftInputMode="adjustResize" in the Activity's manifest then the BottomNavigationView moves above the keyboard.

I need to set adjustResize to enable scrolling to the bottom of the screen while the keyboard is open. However, I do not want the BottomNavigationView to be visible. Can this be done?

How it currently looks:

enter image description here

The layout XML (in reality there would be a FrameLayout where the EditText is and the EditText would be inside it):

<?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>
Conchoid answered 5/2, 2017 at 12:18 Comment(4)
Did you solve this?Sevigny
No I didn't, but one suggestion was to hide everything behind the keyboard when a field is tapped on (including bottom nav bar) then when the user taps the screen above the keyboard or scrolls the keyboard just disappears. It's not great but I think it's a better user experience than the floating nav bar. The Spotify app does this.Conchoid
I'm having the same problem... If you find a solution, please tell me...Luciusluck
Hey All ! I have posted a new answer which actually solves this problem. Writing this comment as I am very late to answer and the answer with max votes doesn't really solves this problem may be that's why OP hasn't accepted it yet. So please go through my answer once.Borrero
F
54

Add this to your activity in the manifest

android:windowSoftInputMode="adjustPan"

So like

<activity android:name=".feature.home.HomeActivity" 
 android:windowSoftInputMode="adjustPan"/>
Fidele answered 5/7, 2017 at 2:46 Comment(3)
This is a good thing to keep the bottom nav view to stick to bottom when keyboard opens but it doesn't allow scroll view to work.Borrero
this is not a solution for bottom navigation.Paralyze
It clearly mentioned in the question that how to do that with adjustResize not with adjustPan.Entomologize
B
8

Solution (or another way to do the same)

I have been through the exact same situation as OP stated, I had a BottomNavigationView obviously at the bottom of the screen and above that there was ScrollView.

Now if we do adjustPan in activity then BottomNavigationView remains at bottom when keyboard appears but the scroll doesn't work.

And if we do adjustResize then scroll works but BottomNavigationView gets pushed on top of keyboard.

I think below can be two approaches for the same.

Approach 1

Simply set the visibility to gone/visible on keyboard show/hide. It is quick work around for the same. You can get a listener for keyboard hide/show event in next approach it self.

To make it look interesting, you can try showing/hiding BottomNavigationView with some sort of animation.

Approach 2

Some better way (the material design way) would be using CoordinatorLayout and scrolling behavior (same as you might have seen CollapsingToolBar).

Below would be the layout file

<?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>

That's it, now you can see the BottomNavigationView hiding/showing on scrolling to bottom and top etc. But there is another problem which you could face, in one scenario i.e. when keyboard is hidden, if the content is too small to scroll,

And the problem is that when keyboard opens and you scroll to the bottom which hides the BottomNavigationView, now if you press the back button keyboard hides but the BottomNavigationView still remains hidden. Now, as content is not scrollable, so if you try to scroll, it doesn't show BottomNavigationView. To reveal it again what you need to do is, make keyboard visible again and then scroll upwards, when BottomNavigationView is shown then press back button.

I tried to solve this problem this way,

Add a Global Listener to find out if keyboard is shown or hidden. The code I used here was, (it is in Kotlin, however you can easily convert it to the Java version if you need that)

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)
}

And the last thing, if you use Support Library version 28.0.0 then you will see that behavior.slideUp(navigation) method is protected, so you can't call it from your activity etc.

However Google's Android team has already made these methods public in new material-components. Check this so just import material-components in your project and use this class instead.

Apart from it you can try some more experiments like programmatically calling slideUp or slideDown on keyboard hide/show etc.

P.S. I have spent good amount of time to come to this fully working approach, so thought to share it here, so that it could save someone's time.

Borrero answered 23/3, 2019 at 14:35 Comment(3)
It's good approach but for me When edit text gain focus keyboard is still shown unless user scrollsPhiz
@Phiz When EditText gains focus, keyboard should display. Did you mean to say when EditText looses focus, keyboard still remains displayed?Borrero
thanks for response, It was just little mistake, Solved alreadyPhiz
A
0

There is another solution, which doesn't require adjustSpan, but it works only for API >= 21. You can detect if keyboard is shown/hidden by tracking system insets. Say you have BottomNavigationView, which is child of LinearLayout and you need to hide it when keyboard is shown:

> LinearLayout
  > ContentView
  > BottomNavigationView

All you need to do is to extend LinearLayout in such way:

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;
    }
}

The idea is that when keyboard is shown, system insets are changed with pretty big .bottom value.

Aldine answered 15/2, 2018 at 18:37 Comment(0)
A
0

In your "Manifest.xml"

<activity
   android:name=".MainActivity"
   android:exported="true"
   android:windowSoftInputMode="adjustPan"> // <- just add this line
</activity>
  1. When a text field gets focus, the system checks the keyboard's height.
  2. With adjustPan, the system shifts the layout up to keep the text field visible.
  3. When the keyboard hides, the layout goes back to normal.

This helps users see what they're typing without manual scrolling. Note that sometimes other options like adjustResize are better, depending on your app's content.

Albania answered 1/10, 2023 at 6:1 Comment(0)
A
-1

Actually there's a simple approach:

<activity
    android:name="MainActivity"
    android:windowSoftInputMode="adjustPan"/>
Adiana answered 25/3, 2022 at 13:37 Comment(0)
R
-2

Some time copy paste from other layout will happen this.In my case i just remove tools:context="Your class name" from layout file.Thanks

Retinoscopy answered 2/2, 2021 at 3:7 Comment(0)
A
-4

As an alternative way with your android:windowSoftInputMode="adjustResize" you can try this.

call this method from your OnCreate- once the keyboard is up you can change visibility of views that you don't need to show! When keyboard is down display them again.

 public void checkKeyBoardUp(){
        rootView.getViewTreeObserver().addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {
            @Override
            public void onGlobalLayout() {
                Rect r = new Rect();
                rootView.getWindowVisibleDisplayFrame(r);
                int heightDiff = rootView.getRootView().getHeight() - (r.bottom - r.top);

                if (heightDiff > 100) { // if more than 100 pixels, its probably a keyboard...
                    //ok now we know the keyboard is up...
                    whatEverView.setVisibility(View.INVISIBLE);

                }else{
                    //ok now we know the keyboard is down...
                    whatEverView.setVisibility(View.VISIBLE);
              }
            }
        });
    }
Atelectasis answered 5/2, 2017 at 12:29 Comment(3)
Its right solution but for proper check keyboard status, use this linkNatka
This doesn't work: white space stay in the place of navbarSevigny
Better try with View.GONE rather than View.INVISIBLEBorrero

© 2022 - 2024 — McMap. All rights reserved.