androidresizeandroid-linearlayoutandroid-softkeyboardwindow-soft-input-mode

How to move the views up while EditText grows with text AND how to retain a view or layout just on top of soft keyboard in fragment?


I have a couple of EditTexts and a Camera and Camcorder ImageViews.

1). I want Camera and Camcorder to be just on top of the soft keyboard when it opened up when EditTexts takes the focus.
2). Also, with this layout when the text that user enters in editTextUserMessage view grows, view grows towards bottom under the keyboard. Instead I want it to grow up so that the spinner and the other EditText can move up. While achieving this, I want 1) to happen…that is I want imageCamera and imageVideo ImageViews to sit just on top of Keyboard.

I tried with different softInputModes in activity and in fragment..but I did not see any improvement in anything I want.
While Move layout up when soft keyboard is shown looks to be promising, keeping the views on top of keyboard happens only when the focus changes so this code can not keep the Cam and Camcorder images on top of Keyboard always.

All soultions just moves the entire layout up which is not I want. Also, this is not an activity but a fragment.
Can you help me ?

Below is the layout of my fragment:

<ScrollView xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@+id/scrollView"
    android:layout_width="match_parent"
    android:layout_height="match_parent">

    <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
        android:id="@+id/linearRootInScroll"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:background="@color/white"
        android:orientation="vertical"
        android:paddingBottom="@dimen/padding_bottom">

        <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:layout_gravity="center"
            android:layout_marginBottom="10dp"
            android:layout_marginLeft="10dp"
            android:layout_marginRight="10dp"
            android:layout_marginTop="10dp"
            android:orientation="vertical">

            <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:layout_gravity="center"
                android:layout_marginLeft="5dp"
                android:orientation="horizontal">

                <TextView
                    android:layout_width="wrap_content"
                    android:layout_height="match_parent"
                    android:layout_gravity="center"
                    android:gravity="center"
                    android:text="@string/prefix_type"
                    android:textAppearance="?android:attr/textAppearanceMedium" />

                <Spinner
                    android:id="@+id/spinnerTypes"
                    android:layout_width="match_parent"
                    android:layout_height="wrap_content"
                    android:layout_weight="1"
                    android:dropDownWidth="wrap_content"
                    android:padding="8dp" />

            </LinearLayout>

            <com.test.shield.views.SearchFriendCompletionView
                android:id="@+id/editTextAddFriend"
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:background="@drawable/underline_edittext"
                android:gravity="left|center"
                android:hint="@string/hint_add_friend"
                android:imeOptions="actionDone"
                android:minHeight="58dp"
                android:paddingLeft="5dp"
                android:paddingRight="5dp"
                android:scrollbars="vertical"
                android:textColorHint="@color/LIGHT_BLACK" />

            <EditText
                android:id="@+id/editTextUserMessage"
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:layout_marginTop="10dp"
                android:background="@drawable/underline_edittext"
                android:gravity="left"
                android:hint="@string/hint_message"
                android:inputType="textCapSentences|textMultiLine"
                android:isScrollContainer="true"
                android:maxLength="140"
                android:minHeight="120dp"
                android:padding="5dp"
                android:scrollbars="vertical"
                android:textColorHint="@color/LIGHT_BLACK" />

            <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
                android:id="@+id/linearCamAndVideo"
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:gravity="start"
                android:orientation="horizontal">

                <ImageView
                    android:id="@+id/imageCamera"
                    android:layout_width="40dp"
                    android:layout_height="40dp"
                    android:layout_marginRight="5dp"
                    android:background="?attr/selectableItemBackground"
                    android:padding="10dp"
                    android:scaleType="center"
                    android:src="@drawable/ic_photo_camera_black_24dp" />

                <ImageView
                    android:id="@+id/imageVideo"
                    android:layout_width="40dp"
                    android:layout_height="40dp"
                    android:background="?attr/selectableItemBackground"
                    android:padding="10dp"
                    android:scaleType="center"
                    android:src="@drawable/ic_videocam_black_24dp" />

            </LinearLayout>

            <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:layout_marginBottom="15dp"
                android:gravity="start"
                android:orientation="vertical">

                <TextView
                    android:id="@+id/textTime"
                    android:layout_width="match_parent"
                    android:layout_height="wrap_content"
                    android:textColor="@color/black" />

            </LinearLayout>
        </LinearLayout>

        <ImageView
            android:id="@+id/imageMap"
            android:layout_width="match_parent"
            android:layout_height="150dp"
            android:layout_gravity="center"
            android:layout_marginLeft="10dp"
            android:layout_marginRight="10dp"
            android:padding="7dp"
            android:paddingBottom="5dp"
            android:scaleType="centerCrop" />
    </LinearLayout>
</ScrollView>


Solution

  • Well, I had to put enough efforts to achieve this.

    For 2) that letting EditText grow upwards so that cursor is visible fix was adding this line in onCreateView() of my Fragment where my above layout is inflated :
    getActivity().getWindow().setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_ADJUST_PAN);

    I tried applying the same bit in manifest for activity but it did not work.

    For 1) that to keep the LinearLayout that has Camera and Camcorder on top of Keyboard when it is visible. Below is the solution that worked perfectly. See the comments within code to understand it:

    /*
    - LinearCamAndVideo is the one I want to keep on top of soft Keyboard when it is visible.
    Without this code, mLinearCamAndVideo will be obscured under Keyboard.
    
    - int mInitialLayoutHeight holds no of pixels that layout is growing when it is changed while user enters text. It grows
    when user enters key to next line. This globalListener will be called for every change that happens in Layout.
    
    - mRootLayout is root layout in above layout.
    
    - mLinearRootInScroll is root in Scrollview */
    mOnGlobalLayoutListener = new ViewTreeObserver.OnGlobalLayoutListener() {
        @Override
        public void onGlobalLayout() {
            if (!isRemoving()) {
                Rect r = new Rect();
                mRootLayout.getWindowVisibleDisplayFrame(r);
    
                int screenHeight = mRootLayout.getRootView().getHeight();
    
                //top of the screen starts with 0, bottom being max number of pixels which is height of screen too.
                int heightDifference = screenHeight - (r.bottom - r.top);
    
                mKeyboardVisible = heightDifference > (screenHeight / 3);
                if (mInitialLayoutHeight == 0) {
                    mInitialLayoutHeight = mLinearCamAndVideo.getBottom();
                }
    
                mLayoutHeightGrown = mLinearCamAndVideo.getBottom() - mInitialLayoutHeight;
    
                if (mKeyboardVisible) {
                    int layoutBottom = mLinearCamAndVideo.getBottom();
                    int padding = heightDifference - layoutBottom + mLayoutHeightGrown;
    
                    /*Setting padding to the parent layout in ScrollView is key as it provides
                    enough extra space so that scrollTo() can move up the mLinearCamAndVideo layout. You do this only when KB is visible.*/
                    mLinearRootInScroll.setPadding(0, 0, 0, padding + Math.round(Converter.convertDpToPixels(getContext(), 30)));
                    mScrollView.scrollTo(0, layoutBottom);
                } else {
                       // Reset the padding when Keyboard is no more visible..
                       mLinearRootInScroll.setPadding(0, 0, 0, 0);
                    mScrollView.scrollTo(0, r.top);
                }
            }
    
        }
    };
    mRootLayout.getViewTreeObserver().addOnGlobalLayoutListener(mOnGlobalLayoutListener);