title: Adjust Scrollview height when keyboard is hidden/visible
body: <p>I have an activity with bunch of controls (EditText, Spinner etc.), with one of the EditText's having a custom keyboard. Here is how my XML looks like</p>
  
  <pre><code>&lt;RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
      xmlns:tools="http://schemas.android.com/tools"
      android:id="@+id/masterRelativeLayout"
      android:orientation="vertical"
      android:layout_width="match_parent"
      android:layout_height="match_parent" &gt;
  
      &lt;ScrollView
          android:id="@+id/mainScrollview"
          android:layout_width="match_parent"
          android:layout_height="wrap_content"
          android:fillViewport="true" &gt;
  
          &lt;LinearLayout
              android:id="@+id/childLinearLayout"
              android:layout_width="match_parent"
              android:orientation="vertical"
              android:layout_height="wrap_content"&gt;
  
              &lt;!-- Many EditText's, Spinners here --&gt;
  
          &lt;/LinearLayout&gt;
      &lt;/ScrollView&gt;
  
      &lt;android.inputmethodservice.KeyboardView
          android:id="@+id/myKeyboardView"
          android:layout_width="fill_parent"
          android:layout_height="wrap_content"
          android:layout_centerHorizontal="true"
          android:focusable="true"
          android:focusableInTouchMode="true"
          android:keyPreviewLayout ="@layout/kbdpreview"
          android:layout_alignParentBottom="true"
          android:visibility="gone" /&gt;
  &lt;/RelativeLayout&gt;
  </code></pre>
  
  <p>Notice that the keyboard view is bottom-aligned, so that it shows up at the bottom of the screen.</p>
  
  <p>The custom keyboard gets hidden and shown on the specific EditText as follows:</p>
  
  <p>These methods are called when a specific EditText in the activity is touched.</p>
  
  <pre><code>private OnTouchListener m_onTouchListenerNotationText = new OnTouchListener()
  {
      @Override
      public boolean onTouch(View v, MotionEvent event)
      {
          if (v == m_notationText)
          {
              // Hide the default keyboard
              getWindow().setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_STATE_ALWAYS_HIDDEN);
              m_notationText.onTouchEvent(event);
              m_customKeyboard.showCustomKeyboard(v);
              AdjustScrollView();
              return true;    // Done with the event
          }
          return false;
      }
  };
  </code></pre>
  
  <p>Whenever the custom keyboard appears on the screen, it hides some of the controls in my view. However, Android framework does not know that this keyboard is being shown so the scrollview does not adjust. The controls remain hidden behind the custom keyboard. Hence, I have implemented a callback in the custom keyboard which gets called when the keyboard is visible.</p>
  
  <pre><code>// This listener is in showCustomKeyboard(...) function
  // Set a static variable m_height and tell the activity to adjust the scrollview after keyboard becomes VISIBLE
  mKeyboardView.getViewTreeObserver().addOnGlobalLayoutListener(new OnGlobalLayoutListener()
  {
      @SuppressLint("NewApi")
      @SuppressWarnings("deprecation")
      @Override
      public void onGlobalLayout()
      {
          int currentapiVersion = android.os.Build.VERSION.SDK_INT;
          if (currentapiVersion &gt;= android.os.Build.VERSION_CODES.JELLY_BEAN)
          {
              mKeyboardView.getViewTreeObserver().removeGlobalOnLayoutListener(this);
          }
          else
          {
              mKeyboardView.getViewTreeObserver().removeOnGlobalLayoutListener(this);
          }
          m_height = mKeyboardView.getHeight();
          Log.d(TAG, "Custom Keyboard now visible, height = " + m_height);
          mHostActivity.AdjustScrollView();
      }
  });
  
  // This listener is in hideCustomKeyboard(...) function
  // Set a static variable m_height and tell the activity to adjust the scrollview after keyboard becomes HIDDEN
  view.getViewTreeObserver().addOnGlobalLayoutListener(new OnGlobalLayoutListener()
  {
      @SuppressLint("NewApi")
      @SuppressWarnings("deprecation")
      @Override
      public void onGlobalLayout()
      {
          int currentapiVersion = android.os.Build.VERSION.SDK_INT;
          if (currentapiVersion &gt;= android.os.Build.VERSION_CODES.JELLY_BEAN)
          {
              view.getViewTreeObserver().removeGlobalOnLayoutListener(this);
          }
          else
          {
              view.getViewTreeObserver().removeOnGlobalLayoutListener(this);
          }
          m_height = 0;
          Log.d(TAG, "Custom Keyboard now hidden");
          mHostActivity.AdjustScrollView();
      }
  });
  </code></pre>
  
  <p>Finally, the scrollview adjustment happens as follows:</p>
  
  <pre><code>public synchronized void AdjustScrollView()
  {
      RelativeLayout rl = (RelativeLayout) findViewById(R.id.masterRelativeLayout);
      int masterHeight = rl.getHeight();
      Log.d(TAG, "Scrollview master relative layout height = " + masterHeight);
  
      LinearLayout ll = (LinearLayout) findViewById(R.id.childLinearLayout);
      int childHeight = ll.getHeight();
      Log.d(TAG, "Scrollview child linear layout height = " + childHeight);
  
      ScrollView scrollView = (ScrollView) findViewById(R.id.mainScrollview);
      if (masterHeight - childHeight - m_customKeyboard.m_height &lt;= 0)
      {
          // Need to adjust scrollview's height
          scrollView.getLayoutParams().height = masterHeight - m_customKeyboard.m_height;
          Log.d(TAG, "Setting scrollview.layoutparams.height = " + (masterHeight - m_customKeyboard.m_height));
      }
      else if (m_customKeyboard.m_height == 0)
      {
          // Need to adjust scrollview's height to full screen
          scrollView.getLayoutParams().height = childHeight;
          Log.d(TAG, "Setting scrollview.layoutparams.height = " + childHeight);
      }
  }
  </code></pre>
  
  <p>AndroidManifest.xml has the following line for this activity:</p>
  
  <pre><code>android:windowSoftInputMode="stateAlwaysHidden|stateUnchanged|adjustResize"
  </code></pre>
  
  <p>This mostly works, with 2 problems:</p>
  
  <p><strong>Problem 1:</strong> When I press long press on the EditText which shows custom keyboard, <strong>sometimes</strong> there is a race condition whereby the default keyboard <strong>AND</strong> custom keyboard both show up momentarily, then the default keyboard goes away (because I am hiding it in m_onTouchListenerNotationText). But in this time, the calculation of AdjustScrollView gets messed up, because now, the master relative layout height is very small (total height - custom keyboard height - default keyboard height). So the scrollview height calculation above is wrong. The scrollview now gets confined to a very tiny area at the top of the screen, followed by white space, followed by my custom keyboard at the bottom. I worked around this problem by adding call to AdjustScrollView in touch listener for the EditText (so whenever this happens, the user can click on that tiny view and the touch listener will adjust the scrollview). This work-around is undesirable, because, then it makes the long-press useless (I want the user to be able to long-press to show the default system menu of cut/copy/paste etc.). The work-around of requiring an additional touch makes this system menu go away.</p>
  
  <p><a href="https://i.stack.imgur.com/PaZWq.png" rel="nofollow noreferrer"><img src="https://i.stack.imgur.com/PaZWq.png" alt="After long press in the EditText - Problem 1"></a></p>
  
  <p><strong>Problem 2:</strong> If the custom keyboard is hidden, The scrollview does not take the entire screen size again. The bottom part of the screen, which was occupied by the custom keyboard, remains blank and the scrollview is only in the top part of the screen.</p>
  
  <p><a href="https://i.stack.imgur.com/1qBhn.png" rel="nofollow noreferrer"><img src="https://i.stack.imgur.com/1qBhn.png" alt="Problem 2"></a></p>