1

I'm using this library: https://github.com/yshrsmz/KeyboardVisibilityEvent to detect when the keyboard is opened or closed and this relies on android:windowSoftInputMode="adjustResize" being input to the Android manifest.

This library works perfectly to detect the opened and closed events of the soft keyboard but my content is pushed out of view because of the adjustResize parameter.

  • Java:

    KeyboardVisibilityEvent.setEventListener(
            AddActivity.this,
            new KeyboardVisibilityEventListener() {
                @Override
                public void onVisibilityChanged(boolean isOpen) {
                    // some code depending on keyboard visiblity status
                    if (noteEditText.isFocused()) {
                        if (isOpen) {
                            Log.d("KB", "Keyboard is open");
                            noteEditText.setLines(12);
                            noteEditText.setCursorVisible(true);
                        } else {
                            Log.d("KB", "Keyboard is closed");
                            noteEditText.setLines(50);
                            noteEditText.setCursorVisible(false);
                        }
                    }
                }
            });
    
    noteEditText.setOnFocusChangeListener(new View.OnFocusChangeListener() {
        @Override
        public void onFocusChange(View v, boolean hasFocus) {
            Log.d("KB", "onFocusChange");
    
            if (firstStart) {
                noteEditText.setLines(12);
                noteEditText.setCursorVisible(true);
                firstStart = false;
            }
        }
    });
    
  • XML:

    <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@+id/add_record"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical"
    android:padding="20dp"
    android:windowSoftInputMode="stateHidden">
    
    <EditText
        android:id="@+id/title_edittext"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:ems="10"
        android:hint="@string/enter_title"
        android:inputType="textCapSentences"
        android:textColor="@color/fontPrimary"
        android:theme="@style/EditTextCustomCursor">
    
        <requestFocus />
    </EditText>
    
    <EditText
        android:id="@+id/note_edittext"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:background="@null"
        android:ellipsize="end"
        android:gravity="top|left"
        android:hint="@string/enter_note"
        android:inputType="textCapSentences|textMultiLine"
        android:lines="50"
        android:maxLines="20"
        android:minLines="5"
        android:paddingLeft="5dp"
        android:scrollHorizontally="false"
        android:scrollbars="vertical"
        android:textColor="@color/fontPrimary"
        android:theme="@style/EditTextCustomCursor" />
    

So this works great by adjusting the lines of the second EditText so then I'm typing above the keyboard but when I close the keyboard, scroll to the bottom of that EditText and click at the bottom, the EditText cursor is placed where I clicked but then it pushes the first EditText and the Support ActionBar out of view and leaves a large gap at the bottom (as can be seen in the image (image 2) below, as where the 'F' is selected, that is the bottom of the EditText).

  • Desired effect (all in the correct position) Desired Effect

  • Actual effect (Support ActionBar and top EditText are moved out of view) Actual Effect

I had also tried using 'adjustNothing' and doing the following, but this doesn't appear to work either as the EditText height won't get changed until the number of lines are changed and the number of lines are only changed when it knows whether or not the keyboard is open or closed.

private void setupListeners() {

    final View activityRootView = getWindow().getDecorView().findViewById(android.R.id.content);
    activityRootView.getViewTreeObserver().addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {
        @Override
        public void onGlobalLayout() {

            View mainView = (LinearLayout) findViewById(R.id.add_record);
            int heightDiff = mainView.getHeight() - noteEditText.getHeight();
            Log.d("KB", "HeightDiff: " + heightDiff);
            if (heightDiff > 1000 || keyboardShown) { // 99% of the time the height diff will be due to a keyboard.
                Log.d("KB", "Keyboard is open");

                if (isKeyboardVisible) {
                    noteEditText.setLines(12);
                    noteEditText.setCursorVisible(true);
                    noteEditText.requestLayout();
                    isKeyboardVisible = false;
                }
            } else {
                Log.d("KB", "Keyboard is closed");

                if (!isKeyboardVisible) {
                    noteEditText.setLines(50);
                    noteEditText.setCursorVisible(false);
                    noteEditText.requestLayout();
                    isKeyboardVisible = true;
                }
            }
        }
    });

    noteEditText.setOnClickListener(new OnClickListener() {
        @Override
        public void onClick(View v) {
            numTimesClicked++;
            Log.d("KB", "onClick: " + numTimesClicked);

            if (clicked) {
                // Run function
                Log.d("KB", "clicked");
                InputMethodManager imm = (InputMethodManager) AddActivity.this.getSystemService(Context.INPUT_METHOD_SERVICE);

                if (imm.isAcceptingText()) {
                    Log.d("KB", "Software Keyboard was shown");
                    isKeyboardVisible = true;
                    keyboardShown = true;
                } else {
                    Log.d("KB", "Software Keyboard was not shown");
                    isKeyboardVisible = false;
                    keyboardShown = false;
                }
            } else {
                Log.d("KB", "scroll");
                clicked = true;
                new Handler().postDelayed(new Runnable() {
                    @Override
                    public void run() {
                        clicked = false;
                    }
                }, 3 * 1000);
            }
        }
    });

    noteEditText.setOnKeyListener(new View.OnKeyListener() {
        @Override
        public boolean onKey(View v, int keyCode, KeyEvent event) {
            if (event.getKeyCode() == KeyEvent.KEYCODE_BACK) {
                Log.d("KB", "closeKeyboard");
                noteEditText.setLines(50);
                noteEditText.setCursorVisible(false);
                noteEditText.requestLayout();
                isKeyboardVisible = false;
            }
            return false;
        }
    });

Therefore, how would I go about achieving the desired effect of adjusting the EditText lines (when the keyboard is opened and closed) and not pushing other content out of view? So then the Support ActionBar and first EditText always remain in the same position and only the second EditText is adjusted when the soft keyboard appears?

Toby Clench
  • 403
  • 1
  • 5
  • 22

2 Answers2

1

I am not sure, but I believe If you keep the layout contents under a ScrollView and everytime the user enters a new line or a new word, you set scrollView.scrollTo(0,0). Also instead of this library, you may use ViewTreeObserver, refer here

Also you may manage this using onFocusChangeListener() which is a better practice.

Community
  • 1
  • 1
Debdeep
  • 752
  • 10
  • 22
  • Thank you for the suggestion with the ScrollView (as this has partially resolved my issue) but is still causing one last issue if the user clicks on a line without having to scroll (see my answer below). – Toby Clench Feb 10 '17 at 10:44
0

I have now managed to resolve this (not the best solution) but it does work. The top EditText and Support ActionBar now never get pushed out of view and the second EditText resizes itself regardless of which line is selected.

Manifest:

<activity android:theme="@style/AppTheme"
        android:name=".activities.AddActivity"
        android:label="@string/add_record"
        android:windowSoftInputMode="stateVisible|adjustResize"
        android:parentActivityName=".MainActivity"
        android:excludeFromRecents="true"/>
    <activity android:theme="@style/AppTheme"
        android:name=".activities.ModifyActivity"
        android:label="@string/modify_record"
        android:windowSoftInputMode="stateAlwaysHidden|adjustResize"
        android:parentActivityName=".MainActivity"
        android:excludeFromRecents="true"/>

Java:

private void setupListeners() {

    final LinearLayout linearLayout = (LinearLayout) findViewById(R.id.add_record);
    if (linearLayout != null) {
        linearLayout.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                Log.d(TAG, "Clicking ll");
                noteEditText.requestFocus();

                InputMethodManager inputMethodManager = (InputMethodManager) getSystemService(Context.INPUT_METHOD_SERVICE);
                inputMethodManager.toggleSoftInputFromWindow(linearLayout.getApplicationWindowToken(),
                        InputMethodManager.SHOW_FORCED, 0);
            }
        });
    }

    KeyboardVisibilityEvent.setEventListener(
            AddActivity.this,
            new KeyboardVisibilityEventListener() {
                @Override
                public void onVisibilityChanged(boolean isOpen) {
                    // some code depending on keyboard visiblity status
                    Log.d(TAG, "Keyboard visibility changed");

                    int currentLine = getCurrentCursorLine(noteEditText);

                    lineCount = noteEditText.getLineCount();

                    if (isOpen && keyboardActuallyOpen) {
                        Log.d(TAG, "Keyboard is open");
                        //keyboardActuallyClosed = false;

                            /*
                            scrollView.fullScroll(View.FOCUS_UP);
                            noteEditText.requestFocus();
                            */

                        if (currentLine < 25) {

                            getWindow().setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_ADJUST_NOTHING);

                            scrollView.scrollTo(0, 0);

                            noteEditText.setMinLines(12);
                            noteEditText.setLines(12);
                            noteEditText.setMaxLines(12);
                            scrollView.scrollTo(0, 0);

                            noteEditText.setVerticalScrollBarEnabled(true);
                            scrollView.setVerticalScrollBarEnabled(false);
                            noteEditText.setCursorVisible(true);

                            scrollView.requestLayout();
                            noteEditText.requestLayout();
                        } else {

                            getWindow().setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_ADJUST_RESIZE);

                            scrollView.scrollTo(0, 0);
                            noteEditText.setMinLines(12);
                            noteEditText.setLines(12);
                            noteEditText.setMaxLines(12);
                            scrollView.scrollTo(0, 0);

                            noteEditText.setVerticalScrollBarEnabled(true);
                            scrollView.setVerticalScrollBarEnabled(false);
                            noteEditText.setCursorVisible(true);
                        }
                    } else {

                        if (!keyboardActuallyOpen) {


                            lineCount = noteEditText.getLineCount();

                            Log.d(TAG, "Keyboard is closed: " + lineCount);
                            noteEditText.setVerticalScrollBarEnabled(false);
                            scrollView.setVerticalScrollBarEnabled(true);
                            noteEditText.setCursorVisible(false);

                            noteEditText.setMinLines(lineCount);
                            noteEditText.setLines(lineCount);
                            noteEditText.setMaxLines(lineCount);
                            scrollView.scrollTo(0, 0);

                            keyboardActuallyOpen = false;

                            //scrollView.requestFocus();
                            //setAdjustResize(1);

                            LinearLayout mainLayout = (LinearLayout) findViewById(R.id.add_record);
                            if (mainLayout != null) {
                                mainLayout.requestFocus();
                            }
                        }

                    }
                }
            });

    noteEditText.setOnFocusChangeListener(new View.OnFocusChangeListener() {
        @Override
        public void onFocusChange(View v, boolean hasFocus) {
            Log.d(TAG, "onFocusChange");

            if (firstStart) {
                scrollView.scrollTo(0, 0);
                noteEditText.setLines(12);
                noteEditText.setCursorVisible(true);
                firstStart = false;
            }

            if (hasFocus) {
                Log.d(TAG, "Has Focus");
                keyboardActuallyOpen = true;
            } else {
                Log.d(TAG, "Lost focus");
                keyboardActuallyOpen = false;
                setAdjustResize(2);
            }
        }
    });
    noteEditText.setOnKeyListener(new View.OnKeyListener() {
        @Override
        public boolean onKey(View v, int keyCode, KeyEvent event) {
            if (event.getKeyCode() == KeyEvent.KEYCODE_BACK) {
                Log.d(TAG, "closeKeyboard");

                keyboardActuallyOpen = false;

                noteEditText.setMinLines(lineCount);
                noteEditText.setLines(lineCount);
                noteEditText.setMaxLines(lineCount);

                noteEditText.setVerticalScrollBarEnabled(false);
                noteEditText.setCursorVisible(false);
                noteEditText.requestLayout();

                scrollView.scrollTo(0, 0);
                scrollView.setVerticalScrollBarEnabled(true);
                scrollView.requestLayout();

                noteEditText.clearFocus();
            }
            return false;
        }
    });


}

Java (sub-classed EditText for keyboard close button pressed):

public class ExtendedEditText extends EditText {

public ExtendedEditText(Context context, AttributeSet attrs, int defStyle) {
    super(context, attrs, defStyle);

}

public ExtendedEditText(Context context, AttributeSet attrs) {
    super(context, attrs);

}

public ExtendedEditText(Context context) {
    super(context);

}

@Override
public boolean onKeyPreIme(int keyCode, KeyEvent event) {
    if (event.getKeyCode() == KeyEvent.KEYCODE_BACK) {
        dispatchKeyEvent(event);
        return false;
    }
    return super.onKeyPreIme(keyCode, event);
}

}

XML

    <?xml version="1.0" encoding="utf-8"?>
<ScrollView xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@+id/add_scrollView"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent"
    android:descendantFocusability="beforeDescendants"
    android:focusableInTouchMode="true"
    android:fillViewport="true">

    <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
        android:id="@+id/add_record"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:orientation="vertical"
        android:padding="20dp"
        android:focusable="true"
        android:focusableInTouchMode="true">

        <EditText
            android:id="@+id/title_edittext"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:ems="10"
            android:hint="@string/enter_title"
            android:inputType="textCapSentences"
            android:textColor="@color/fontPrimary"
            android:theme="@style/EditTextCustomCursor">
        </EditText>

        <com.securenotes.utils.ExtendedEditText
            android:id="@+id/note_edittext"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:background="@null"
            android:ellipsize="end"
            android:gravity="top|left"
            android:hint="@string/enter_note"
            android:inputType="textCapSentences|textMultiLine"
            android:lines="50"
            android:maxLines="20"
            android:minLines="5"
            android:paddingLeft="5dp"
            android:scrollHorizontally="false"
            android:scrollbars="vertical"
            android:textColor="@color/fontPrimary"
            android:theme="@style/EditTextCustomCursor" />

    </LinearLayout>
</ScrollView>
Toby Clench
  • 403
  • 1
  • 5
  • 22