37

I've seen in some applications the layout shifts when soft keyboard is shown. This is certainly not adjustPan because the whole layout (probably inner layout) shifts, not only the current EditText. This is for instance in Evernote login screen. Can you advice how this made?

Eugene
  • 59,186
  • 91
  • 226
  • 333
  • Is your problem that your Layout shifts up when keyboard is shown? – Lalit Poptani Sep 09 '11 at 11:21
  • 1
    The question is how to do so. – Eugene Sep 09 '11 at 11:32
  • Means you don't want that your Layout should pull up, right? – Lalit Poptani Sep 09 '11 at 11:57
  • 2
    If you would set `adjustPan` option for your activity and when your soft keyboard would be shown, the UI would be shifted up in order to show the editText you're currently input text to. This is perfectly fine. My question is how to make it possible not make the whole layout visible instead of only active editText(s). – Eugene Sep 09 '11 at 12:23
  • 1
    Exactly not getting you, you want only EditText to be visible instead of the whole layout. It would be better If you attach some screen shots. – Lalit Poptani Sep 09 '11 at 12:34

6 Answers6

70

Here's a solution that works like the Evernote login screen:

First, define a class that will be your special LinearLayout like this:

public class MyLayout extends LinearLayout {

public MyLayout(Context context, AttributeSet attrs) {
    super(context, attrs);
}

public MyLayout(Context context) {
    super(context);
}

private OnSoftKeyboardListener onSoftKeyboardListener;

@Override
protected void onMeasure(final int widthMeasureSpec, final int heightMeasureSpec) {
    if (onSoftKeyboardListener != null) {
        final int newSpec = MeasureSpec.getSize(heightMeasureSpec); 
        final int oldSpec = getMeasuredHeight();
        if (oldSpec > newSpec){
            onSoftKeyboardListener.onShown();
        } else {
            onSoftKeyboardListener.onHidden();
        }
    }
    super.onMeasure(widthMeasureSpec, heightMeasureSpec);
}

public final void setOnSoftKeyboardListener(final OnSoftKeyboardListener listener) {
    this.onSoftKeyboardListener = listener;
}

public interface OnSoftKeyboardListener {
    public void onShown();
    public void onHidden();
}

}

This layout listens to measure changes, and if new measurements are < than the old ones, that means part of the screen is eaten by soft keyboard.

Though, for it to work, in your manifest you need to set android:windowSoftInputMode="adjustResize" so the content will be resized and not just shifted.

And the whole system works as follows: You have your layout:

<MyLayout id="layout">
  <SomeImage id="image"/>
  <SomeText>
  <SomeInput>
</MyLayout>

It's like evernotes login screen. Then, in your activity:

((MyLayout)findViewById(R.id.layout)).setOnSoftKeyboardListener(new OnSoftKeyboardListener() {
        @Override
        public void onShown() {
            findViewById(R.id.image).setVisibility(View.GONE);
        }
        @Override
        public void onHidden() {
            findViewById(R.id.image).setVisibility(View.VISIBLE);
        }
    });

Then go to manifest.xml and set

android:windowSoftInputMode="adjustResize"

What will happen, is when soft keyboard is shown, it'll hide the image and will resize the rest of content. (You can actually see how text is resized in Evernote)

Image hide is, of course, one of the many things you can do. But you must be careful, since different layout changes will also call onMeasure.

Of course it's a dirty variant. You need to check for orientation changes, and the right time when actually take the measurements, and maybe some more logic when comparing the new specs with the old ones. But i think this is the only way to do it.

QED
  • 9,803
  • 7
  • 50
  • 87
Alex Orlov
  • 18,077
  • 7
  • 55
  • 44
  • 1
    We use the same approach in our projects. Hate it but seems it's the only way to hook IME shown/hidden events on Android 2.x. – Michael Sep 10 '11 at 20:49
  • 4
    This sometimes has some bugs. This version here is better: http://stackoverflow.com/questions/2150078/android-is-software-keyboard-shown/4737265#4737265 – Patrick Boos Oct 19 '11 at 09:00
  • 3
    Doesn't work correctly on Galaxy S4. To correct need to change if (oldSpec > newSpec) .. else ... to replace the 'else' with if (oldSpec < newSpec). The current code fires onHidden() when the measurement stays the same. – Jonathan Wareham Oct 18 '13 at 10:54
  • @JonathanWareham as mentionned in the other linked answer, you should also take an arbitrary margin of something like a hundred pixels to avoid false-positives. – Marc Plano-Lesay Sep 02 '15 at 15:19
10

Use "adjustResize" instead of "adjustPan" in AndroidManifest.xml

<activity
    ...
    android:windowSoftInputMode="adjustResize" />

From the documentation:

"adjustResize"
The activity's main window is always resized to make room for the soft keyboard on screen.

"adjustPan"
The activity's main window is not resized to make room for the soft keyboard. Rather, the contents of the window are automatically panned so that the current focus is never obscured by the keyboard and users can always see what they are typing. This is generally less desirable than resizing, because the user may need to close the soft keyboard to get at and interact with obscured parts of the window.

Community
  • 1
  • 1
naXa stands with Ukraine
  • 35,493
  • 19
  • 190
  • 259
2

This worked for me..Put this is your oncreate

getWindow().setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_STATE_VISIBLE|WindowManager.LayoutParams.SOFT_INPUT_ADJUST_RESIZE);
Madhav
  • 283
  • 3
  • 13
2

The selected answer doesn't work for full-screen mode. Following one line solution worked for me:

 AndroidBug5497Workaround.assistActivity(this);

copy the class AndroidBug5497Workaround from:

Android How to adjust layout in Full Screen Mode when softkeyboard is visible

Community
  • 1
  • 1
M. Usman Khan
  • 3,689
  • 1
  • 59
  • 69
  • Thanks, it's working. In my case a layout is too complex, and after some positioning inside an activity when a keyboard appears it can crash (with Out of Memory). – CoolMind Nov 02 '16 at 18:51
  • These workarounds are dangerous because if libraries are updated, conflicts unknowingly arise, in fact it doesn't work for me. Sometimes the best solution is not the workaround, but to look at the problem from another perspective. – AlexPad Jun 17 '19 at 19:24
0

use scroll view in your layout inside the parent and remove the adjustpan or adjustresize setting from manifest file. ScrollView at your layout will give you the free functionality to scroll you pan or layout with the given layout and also protect your layout to override the toolbar or actionbar and also will not hide the buttons or textfields inside the layout. Remember you have to use the ScrollView inside the base layout, so this scrollview will work as the base layout for the whole screen. example

<LinearLayout
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:orientation="vertical" >

<ScrollView
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent"
    android:fillViewport="true"
    android:scrollbarStyle="insideInset"
    android:scrollbars="vertical" >

    <LinearLayout
        android:layout_width="fill_parent"
        android:layout_height="fill_parent"
        android:orientation="vertical" >

        <!-- Add here which you want -->
    </LinearLayout>
</ScrollView>

Nikolay Kostov
  • 16,433
  • 23
  • 85
  • 123
Ankush Bist
  • 1,862
  • 1
  • 15
  • 32