58

I have a view with a Edittext field on top of an ImageView. When the keyboard comes up I want the window to resize so that EditText is no longer hidden by the keyboard. In the AndroidManifest file I declared android:windowSoftInputMode="adjustResize" and the screen is resized but the issue is that I want the ImageView to not be re-sized. How can I make the ImageView unaffected?

Could I inflate an additional layout with just the ImageView or will the resize still affect it? enter image description here

pdfj
  • 769
  • 1
  • 6
  • 12

8 Answers8

97

The full solution involves a few key points

  • Use RelativeLayout, so that Views can be setup to overlap one another
  • Align the EditText with the bottom of the Windows using android:layout_alignParentBottom="true"
  • Use android:windowSoftInputMode="adjustResize" in your manifest, so that the bottom of the Window changes when the keyboard pops up (as you mentioned)
  • Put the ImageView inside a ScrollView so that the ImageView can be larger than the Window, and disable scrolling on the ScrollView by using ScrollView#setEnabled(false)

Here is the layout file

<RelativeLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context="com.so3.MainActivity">
    <ScrollView
        android:id="@+id/scroll"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content">
        <ImageView
            android:layout_width="fill_parent"
            android:layout_height="wrap_content"
            android:adjustViewBounds="true"
            android:src="@drawable/stickfigures"/>
    </ScrollView>
    <EditText
        android:layout_width="fill_parent"
        android:layout_height="wrap_content"
        android:layout_alignParentBottom="true"
        android:background="@android:color/holo_blue_bright"
        android:text="Please enter text"
        android:textSize="40sp"
        android:gravity="center_horizontal"/>
</RelativeLayout>

Here is my Activity

package com.so3;

import android.app.Activity;
import android.os.Bundle;
import android.widget.ScrollView;

public class MainActivity extends Activity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        ScrollView sv = (ScrollView)findViewById(R.id.scroll);
        sv.setEnabled(false);
    }
}

My AndroidManifest

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"    package="com.so3" >
    <application
        android:allowBackup="true"
        android:icon="@drawable/ic_launcher"
        android:label="@string/app_name"
        android:theme="@style/AppTheme" >
        <activity
            android:name="com.so3.MainActivity"
            android:windowSoftInputMode="adjustResize"
            android:label="@string/app_name" >
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />
                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>
    </application>
</manifest>

Screen shots of my solution

screenshot 1 screenshot 2

Brian Attwell
  • 9,239
  • 2
  • 31
  • 26
  • 2
    Making it a scrollview and disabling scroll is the part I was missing. I will try and implement it tomorrow. – pdfj Jan 18 '14 at 10:03
  • 1
    @BrianAttwell What about Fragment? – Pratik Butani May 22 '14 at 05:57
  • after search for more than couple of hours this works well with me ! – Menna-Allah Sami Dec 23 '14 at 14:05
  • 1
    +1. Good solution, but setEnabled(false) of ScrollView doesn't work for me. I've used wrapper of ScrollView for disabling scrolling http://stackoverflow.com/a/5763815/1225669 – valerybodak Oct 19 '15 at 10:23
  • Could I do the same but with 1 EditText + 1 Button under it ? – An-droid Mar 22 '16 at 11:25
  • @anivaler I had same problem. I took that answer and just made a ScrollView that was permanently locked. A benefit of doing it that way is that we no longer have to give our ScrollView an id and call findViewById in our activity. – tir38 Jul 14 '16 at 02:20
  • Adding ImageView inside a Scrollview works like a magic.Thanks. – B.shruti Oct 16 '17 at 12:24
  • 4
    But what if the case is width='match_parent" and image is small,this way imageview is not taking full screen and also for making it full screen, adding scrollview fillViewport is again making the image resized on soft keyboard pop up, please help. – B.shruti Oct 27 '17 at 07:17
  • Hey @BrianAttwell can you suggestion this question https://stackoverflow.com/questions/37760544/image-resizing-issue-when-keyboard-open-in-android-mobile – Hardik Godhani Jul 13 '18 at 10:52
  • YOU HAVE SAVED ME!!! I needed to be able to leave my activity resizable to control FAB behavior when softInput keyboard is shown, but I also had a background set that I could not allow to be resized. In case this applies to anyone in the future: I used a RelativeLayout inside of a ScrollView inside of a CoordinatorLayout inside of a DrawerLayout...and set a background to the RelativeLayout. The Fab is inside of the CoordinatorLayout obviously and now moves with the keyboard while leaving the background unaffected. – Xijukx Aug 05 '19 at 01:40
3

Adding ScrollView was making my image scrollable which I wanted to avoid so I used this samples-keyboardheight calculator and onKeyboardHeightChanged recalculated position of the bottom Edittext placed it above Keyboard and used this flag in Manifest.

android:windowSoftInputMode="adjustNothing|stateHidden"

Here is KeyboardHeightProvider :

import android.app.Activity;
import android.content.res.Configuration;
import android.graphics.Point;
import android.graphics.Rect;
import android.graphics.drawable.ColorDrawable;
import android.view.Gravity;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewTreeObserver.OnGlobalLayoutListener;
import android.view.WindowManager.LayoutParams;
import android.widget.PopupWindow;
/**
 * The keyboard height provider, this class uses a PopupWindow
 * to calculate the window height when the floating keyboard is opened and closed. 
 */
public class KeyboardHeightProvider extends PopupWindow {

    /** The tag for logging purposes */
    private final static String TAG = "sample_KeyboardHeightProvider";

    /** The keyboard height observer */
    private KeyboardHeightObserver observer;

    /** The cached landscape height of the keyboard */
    private int keyboardLandscapeHeight;

    /** The cached portrait height of the keyboard */
    private int keyboardPortraitHeight;

    /** The view that is used to calculate the keyboard height */
    private View popupView;

    /** The parent view */
    private View parentView;

    /** The root activity that uses this KeyboardHeightProvider */
    private Activity activity;

    /** 
     * Construct a new KeyboardHeightProvider
     * 
     * @param activity The parent activity
     */
    public KeyboardHeightProvider(Activity activity) {
        super(activity);
        this.activity = activity;

        LayoutInflater inflator = (LayoutInflater) activity.getSystemService(Activity.LAYOUT_INFLATER_SERVICE);
        this.popupView = inflator.inflate(R.layout.popupwindow, null, false);
        setContentView(popupView);

        setSoftInputMode(LayoutParams.SOFT_INPUT_ADJUST_RESIZE | LayoutParams.SOFT_INPUT_STATE_ALWAYS_VISIBLE);
        setInputMethodMode(PopupWindow.INPUT_METHOD_NEEDED);

        parentView = activity.findViewById(android.R.id.content);

        setWidth(0);
        setHeight(LayoutParams.MATCH_PARENT);

        popupView.getViewTreeObserver().addOnGlobalLayoutListener(new OnGlobalLayoutListener() {

                @Override
                public void onGlobalLayout() {
                    if (popupView != null) {
                        handleOnGlobalLayout();
                    }
                }
            });
    }

    /**
     * Start the KeyboardHeightProvider, this must be called after the onResume of the Activity.
     * PopupWindows are not allowed to be registered before the onResume has finished
     * of the Activity.
     */
    public void start() {

        if (!isShowing() && parentView.getWindowToken() != null) {
            setBackgroundDrawable(new ColorDrawable(0));
            showAtLocation(parentView, Gravity.NO_GRAVITY, 0, 0);
        }
    }

    /**
     * Close the keyboard height provider, 
     * this provider will not be used anymore.
     */
    public void close() {
        this.observer = null;
        dismiss();
    }

    /** 
     * Set the keyboard height observer to this provider. The 
     * observer will be notified when the keyboard height has changed. 
     * For example when the keyboard is opened or closed.
     * 
     * @param observer The observer to be added to this provider.
     */
    public void setKeyboardHeightObserver(KeyboardHeightObserver observer) {
        this.observer = observer;
    }

    /**
     * Get the screen orientation
     *
     * @return the screen orientation
     */
    private int getScreenOrientation() {
        return activity.getResources().getConfiguration().orientation;
    }

    /**
     * Popup window itself is as big as the window of the Activity. 
     * The keyboard can then be calculated by extracting the popup view bottom 
     * from the activity window height. 
     */
    private void handleOnGlobalLayout() {

        Point screenSize = new Point();
        activity.getWindowManager().getDefaultDisplay().getSize(screenSize);

        Rect rect = new Rect();
        popupView.getWindowVisibleDisplayFrame(rect);

        // REMIND, you may like to change this using the fullscreen size of the phone
        // and also using the status bar and navigation bar heights of the phone to calculate
        // the keyboard height. But this worked fine on a Nexus.
        int orientation = getScreenOrientation();
        int keyboardHeight = screenSize.y - rect.bottom;

        if (keyboardHeight == 0) {
            notifyKeyboardHeightChanged(0, orientation);
        }
        else if (orientation == Configuration.ORIENTATION_PORTRAIT) {
            this.keyboardPortraitHeight = keyboardHeight; 
            notifyKeyboardHeightChanged(keyboardPortraitHeight, orientation);
        } 
        else {
            this.keyboardLandscapeHeight = keyboardHeight; 
            notifyKeyboardHeightChanged(keyboardLandscapeHeight, orientation);
        }
    }

    /**
     *
     */
    private void notifyKeyboardHeightChanged(int height, int orientation) {
        if (observer != null) {
            observer.onKeyboardHeightChanged(height, orientation);
        }
    }

    public interface KeyboardHeightObserver {
        void onKeyboardHeightChanged(int height, int orientation);
    }
}

popupwindow.xml :

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@+id/popuplayout"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:background="@android:color/transparent"
    android:orientation="horizontal"/>

Here is MainActivity.java :

import android.os.Bundle;
import android.support.v7.app.AppCompatActivity;
import android.view.View;
import android.view.ViewGroup;

public class MainActivity extends AppCompatActivity  implements KeyboardHeightProvider.KeyboardHeightObserver {

    private KeyboardHeightProvider keyboardHeightProvider;

    private ViewGroup relativeView;
    private float initialY;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        keyboardHeightProvider = new KeyboardHeightProvider(this);

        relativeView = findViewById(R.id.bottomEditor);
        relativeView.post(() -> initialY = relativeView.getY());

        View view = findViewById(R.id.activitylayout);
        view.post(() -> keyboardHeightProvider.start());


    }

    @Override
    public void onKeyboardHeightChanged(int height, int orientation) {
        if(height == 0){
            relativeView.setY(initialY);
            relativeView.requestLayout();
        }else {

            float newPosition = initialY - height;
            relativeView.setY(newPosition);
            relativeView.requestLayout();
        }
    }

    @Override
    public void onPause() {
        super.onPause();
        keyboardHeightProvider.setKeyboardHeightObserver(null);
    }

    @Override
    public void onResume() {
        super.onResume();
        keyboardHeightProvider.setKeyboardHeightObserver(this);
    }

    @Override
    public void onDestroy() {
        super.onDestroy();
        keyboardHeightProvider.close();
    }
}

activity_main.xml :

<?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"
    xmlns:tools="http://schemas.android.com/tools"
    android:id="@+id/activitylayout"
    android:layout_width="match_parent"
    android:layout_height="match_parent">

    <ImageView
        android:id="@+id/imageView2"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:adjustViewBounds="true"
        android:scaleType="fitCenter"
        />

    <RelativeLayout
        android:id="@+id/bottomEditor"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_alignParentBottom="true"
        >

        <EditText
            android:id="@+id/edit_message"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:layout_margin="4dp"
            android:layout_toStartOf="@+id/btn_send"
            android:hint="Add caption"
            android:paddingBottom="12dp"
            android:paddingLeft="8dp"
            android:paddingRight="8dp"
            android:paddingStart="8dp"
            android:paddingTop="12dp"
            />

        <ImageButton
            android:id="@+id/btn_send"
            android:layout_width="48dp"
            android:layout_height="48dp"
            android:layout_alignBottom="@+id/edit_message"
            android:layout_alignParentEnd="true"
            android:layout_alignParentRight="true"
            android:layout_marginEnd="4dp"
            android:layout_marginRight="4dp"
            app:srcCompat="@android:drawable/ic_menu_send"
            />

    </RelativeLayout>
</RelativeLayout>

P.S. : Keyboard height calculation code is copied from siebeprojects

Here is demo example app of implementation.

Nilesh Deokar
  • 2,975
  • 30
  • 53
1
final View activityRootView = findViewById(R.id.mainScroll);

activityRootView.getViewTreeObserver().addOnGlobalLayoutListener(
        new OnGlobalLayoutListener() {

            @Override
            public void onGlobalLayout() {
                int heightView = activityRootView.getHeight();
                int widthView = activityRootView.getWidth();
                if (1.0 * widthView / heightView > 1) {

                    Log.d("keyboarddddd      visible", "no");
                    relativeLayoutForImage.setVisibility(View.GONE);
                    relativeLayoutStatic.setVisibility(View.GONE);
                    //Make changes for Keyboard not visible


                } else {

                    Log.d("keyboarddddd      visible ", "yes");

                    relativeLayoutForImage.setVisibility(View.VISIBLE);
                    relativeLayoutStatic.setVisibility(View.VISIBLE);
                    //Make changes for keyboard visible


                }
            }
        });
Haresh Chaudhary
  • 4,390
  • 1
  • 34
  • 57
  • this code really work , I solve this type of problem using this code please try this code . It is very helpfull to you . – miral patel Mar 28 '14 at 12:49
  • Hi miral, I have one edittext in my layout which is move on touch, My problem is that when i move edit text top of screen and open keyboard at that time edit text not visible it's gone up when screen resize, but i want when key board open at that time edit text on top of keyboard, do you have any idea? Thanks. – Patel Hiren Jun 14 '15 at 06:55
0

For me i did not want to assume that keyboards heights are a certain measurement. Whatever view your concerned about make a onTouchListener and then do this:

    setOnTouchListener(new OnTouchListener()  {



        Runnable shifter=new Runnable(){
            public void run(){
                try {
                    int[] loc = new int[2];                 
                    //get the location of someview which gets stored in loc array
                    findViewById(R.id.someview).getLocationInWindow(loc);
                    //shift so user can see someview
                    myscrollView.scrollTo(loc[0], loc[1]);   
                }
                catch (Exception e) {
                    e.printStackTrace();
                }   
            }}
        };

        Rect scrollBounds = new Rect();
        View divider=findViewById(R.id.someview);
        myscollView.getHitRect(scrollBounds);
        if (!divider.getLocalVisibleRect(scrollBounds))  {
            // the divider view is NOT  within the visible scroll window thus we need to scroll a bit.
            myscollView.postDelayed(shifter, 500);
        }



    });

//essentially we make a runnable that scrolls to a new location of some view that you WANT visible on the screen. you execute that runnable only if its not within the scrollviews bounds (its not on the screen). This way it shifts the scrollview to the referenced view (in my case 'someview' which was a line divider).

j2emanue
  • 60,549
  • 65
  • 286
  • 456
  • This does not get executed in the first tap, in my case the second tap makes it work. – User3 Aug 11 '14 at 12:59
  • its probably how your registering the ontouchlistener or theirs a view on focus changed listener consuming the touch event etc. I'd have to see code. – j2emanue Aug 11 '14 at 14:31
0

In my opinion the easiest way to do this it is this combination of the two changes:

android:windowSoftInputMode="adjustResize"

in your AndroidManifest.xml

+

getWindow().setBackgroundDrawable(your_image_drawable);

in your activity in @onCreate() method

It works for me.

valerybodak
  • 4,195
  • 2
  • 42
  • 53
  • Is there a way to use this method and yet preserve the aspect ratio of your image? – jk7 Jul 20 '17 at 16:39
0

The best solution is to use a DialogFragment

Show dialog

DialogFragment.show(getSupportFragmentManager(), DialogFragment.TAG);

Full screen

@NonNull
@Override
public Dialog onCreateDialog(Bundle savedInstanceState) {
    Dialog dialog = new Dialog(getActivity(), R.style.MainDialog) { //set the style, the best code here or with me, we do not change
        @Override
        public void onBackPressed() {
            super.onBackPressed();
            getActivity().finish();
        }
    };
    return dialog;
}

Style

<style name="MainDialog" parent="@android:style/Theme.Dialog">
        <item name="android:windowBackground">@android:color/transparent</item>
        <item name="android:windowFrame">@null</item>
        <item name="android:windowNoTitle">true</item>
        <item name="android:windowIsFloating">false</item>
        <item name="android:windowIsTranslucent">true</item>
        <item name="android:windowContentOverlay">@null</item>
        <item name="android:background">@null</item>
        <item name="android:windowAnimationStyle">@null</item>
    </style>

Layout Activity

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:background="@color/black">

    <ImageView
        android:layout_width="match_parent"
        android:layout_height="match_parent" />

</RelativeLayout>

Layout dialog fragment

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:background="@color/transparent">

    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="50dp"
        android:layout_alignParentBottom="true"
        android:layout_alignParentStart="true"
        android:background="@color/background_transparent_60"
        android:gravity="center_vertical">

        <EditText
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:layout_margin="@dimen/spacing_1_8dp"
            android:layout_marginLeft="@dimen/spacing_1_8dp"
            android:layout_marginRight="@dimen/spacing_1_8dp"
            android:layout_weight="1"
            android:hint="@string/comment_entry_hint"
            android:inputType="textMultiLine"
            android:maxLines="4"
            android:textColor="@color/white"
            android:textColorHint="@color/secondary_text_hint"
            android:textSize="@dimen/text_2_12sp" />

        <ImageView
            android:layout_width="@dimen/livestream_comment_height"
            android:layout_height="@dimen/livestream_comment_height"
            android:layout_margin="@dimen/spacing_1_8dp"
            android:src="@drawable/ic_send" />

    </LinearLayout>

</RelativeLayout>
Nankai
  • 931
  • 9
  • 21
0

The solution that worked for me was in AndroidManifest.xml in that activity tag just put

android:windowSoftInputMode="stateHidden|adjustResize|adjustNothing"

All set..Hope this will work for you.

Ali Nawaz
  • 2,016
  • 20
  • 30
-9
    final View activityRootView = findViewById(R.id.mainScroll);

    activityRootView.getViewTreeObserver().addOnGlobalLayoutListener(
            new OnGlobalLayoutListener() {


                @Override
                public void onGlobalLayout() {
                    int heightView = activityRootView.getHeight();
                    int widthView = activityRootView.getWidth();
                    if (1.0 * widthView / heightView > 1) {

                        Log.d("keyboarddddd      visible", "no");
                        relativeLayoutForImage.setVisibility(View.GONE);
                        relativeLayoutStatic.setVisibility(View.GONE);
                        //Make changes for Keyboard not visible
                        //relativeLayoutForImage.setVisibility(View.VISIBLE);
                        //relativeLayoutStatic.setVisibility(View.VISIBLE);

                    } else {

                        Log.d("keyboarddddd      visible ", "yes");

                        relativeLayoutForImage.setVisibility(View.VISIBLE);
                        relativeLayoutStatic.setVisibility(View.VISIBLE);
                        //Make changes for keyboard visible

                    //  relativeLayoutForImage.setVisibility(View.GONE);
                        //relativeLayoutStatic.setVisibility(View.GONE);
                    }
                }
            });
Ean V
  • 5,091
  • 5
  • 31
  • 39