1

I'm currently developing a simple Notes application where the user can input a title and the content of their note. What I am looking to achieve is that when the user clicks the note content (EditText) the soft keyboard comes up and only the note content EditText reduces in size (resizes) whilst everything else remains in the same position.

My current implementation can be seen below:

Manifest:

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

XML - Add Activity

    <?xml version="1.0" encoding="utf-8"?>
<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">

    <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>

    <ScrollView xmlns:android="http://schemas.android.com/apk/res/android"
        android:id="@+id/modify_scrollview"
        android:layout_width="fill_parent"
        android:layout_height="fill_parent"
        android:fitsSystemWindows="false"
        android:isScrollContainer="false"
        android:fillViewport="true">

        <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:paddingLeft="5dp"
            android:scrollHorizontally="false"
            android:textColor="@color/fontPrimary"
            android:theme="@style/EditTextCustomCursor" />
    </ScrollView>

</LinearLayout>

Java - Add Activity

private int screenHeight;
private int actionBarHeight = 350;
private int keyboardHeight;

...

private void setupListeners() {

    final LinearLayout layout = (LinearLayout) findViewById(R.id.add_record);
    layout.getViewTreeObserver().addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {

        @Override
        public void onGlobalLayout() {
            Rect r = new Rect();
            layout.getWindowVisibleDisplayFrame(r);

            screenHeight = layout.getRootView().getHeight();
            keyboardHeight = screenHeight - (r.bottom - r.top);
            Log.d("Keyboard Size", "Size: " + keyboardHeight);

        }
    });

    KeyboardVisibilityEvent.setEventListener(
            AddActivity.this,
            new KeyboardVisibilityEventListener() {
                @Override
                public void onVisibilityChanged(boolean isOpen) {

                    if (isOpen) {
                        Log.d("KB", "openKeyboard");
                        scrollView.setLayoutParams(new LinearLayout.LayoutParams(
                                LinearLayout.LayoutParams.FILL_PARENT, screenHeight - actionBarHeight - keyboardHeight));
                    } else {
                        Log.d("KB", "closeKeyboard");
                        scrollView.setLayoutParams(new LinearLayout.LayoutParams(
                                LinearLayout.LayoutParams.FILL_PARENT, LinearLayout.LayoutParams.FILL_PARENT));
                    }
                }
            });
}

This is using the Keyboard library (https://github.com/yshrsmz/KeyboardVisibilityEvent) to detect when the keyboard is opened or closed. This works perfectly and the height / layout is adjusted just how I want it to look but only if the user clicks at the top of the EditText. If the user clicks at the bottom of the EditText (if they have entered a long note) then the whole layout gets pushed up leaving a large gap at the bottom of the page.

Therefore, is there any way how wherever in the EditText / ScrollView the user clicks, for it to only adjust that one EditText in height and leave the other EditText in place at the top of the screen without pushing it and the SupportActionBar out of view? Also, the ScrollView is being used to achieve the vertical scrollbar on the right side of the screen - if this same behaviour can be achieved using just the EditText, then I would remove the ScrollView altogether.

EDIT - Add Photos

Image 1: Long note content (bottom of note content is at the bottom of the scrollView (which cannot be seen, until scrolled))

Clicking top half of note EditText

Image 2: Same note but clicking at the bottom, forces the top EditText and Support ActionBar out of view whilst leaving a gap at the bottom.

Clicking bottom half of note EditText

Explanation: Where the F is highlighted (in Image 2) that is the bottom of the EditText / ScrollView so you can see the large gap created between the top of the soft keyboard and the bottom of the EditText / ScrollView

Desired behaviour: Clicking anywhere in the bottom EditText should only resize that particular EditText to make room for the soft keyboard and ensure that this EditText is above the soft keyboard so the user can see what they are typing whilst the top EditText remains in the same position throughout.

Toby Clench
  • 403
  • 1
  • 5
  • 22

2 Answers2

1

Its because you're adding edittext in a scroll view. why do you even need scroll view? scroll view have a property of going to specific line when keyboard pop-up which is causing this behavior. if you really want to use scrollview, then add master layout as scrollview. add one direct child aka linear layout in there and add all the content in that linear layout.

Usman Ghauri
  • 931
  • 1
  • 7
  • 26
  • As described in my question, the ScrollView is being used to achieve the scroll bar on the right side (when you are scrolling, the scrollbar appears on the right side) - can this be achieved by just using EditText alone? & I have already tried setting the ScrollView as the master layout but this causes further issues, as when the user is typing (in the note EditText) it scrolls the page and still forces the top EditText and Support ActionBar out of view, which the current implementation doesn't do. Currently, it only gets forced out of view when clicking the bottom of the ScrollView. – Toby Clench Feb 08 '17 at 10:02
  • 1
    yes i know why you need that scroll bar. and if you add multi line tag in your edittext it will automatically show scrollbars there. no need to add scrollview for that .. this is what i use for that long message edittext android:inputType="textMultiLine" android:lines="8" android:maxLines="10" android:minLines="6" – Usman Ghauri Feb 08 '17 at 10:05
  • I have removed the ScrollView completely and using the min, max lines does prevent from the content being pushed up but what I need is the scroll bar on the right (not showing when scrolling the EditText), the note EditText to fill all of the available space when the keyboard is closed & also, when scrolling the EditText, sometimes it thinks it's a click and shows the keyboard instead of scrolling (didn't have this issue with the ScrollView) – Toby Clench Feb 08 '17 at 10:14
  • limit edittext height with specific dp and it will show scrollbars – Usman Ghauri Feb 08 '17 at 11:06
0

I have managed to resolve most of this by doing the following:

  • Removing the ScrollView
  • Subclassing EditText (to receive the close keyboard button)
  • Adding a height-change listener
  • Adding the scroll bars property to the EditText

Manifest:

<activity android:theme="@style/AppTheme"
        android:name=".AddActivity"
        android:label="@string/add_record"
        android:windowSoftInputMode="adjustNothing"
        android:parentActivityName=".MainActivity"
        android:excludeFromRecents="true"/>

XML - Add Activity:

    <?xml version="1.0" encoding="utf-8"?>
<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>

    <com.securenotes.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>

Java - Add Activity:

private Boolean initialStart = true;
private Boolean isOpened = false;

...

private void setupListeners() {

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

            int heightDiff = activityRootView.getRootView().getHeight() - activityRootView.getHeight();
            Log.d("KB", "HeightDiff: " + heightDiff);
            if (heightDiff > 100) { // 99% of the time the height diff will be due to a keyboard.

                if (!isOpened && initialStart) {
                    Log.d("KB", "1) openKeyboard");
                    //Do two things, make the view top visible and the editText smaller
                    noteEditText.setLines(15);
                    noteEditText.requestLayout();
                    initialStart = false;
                    isOpened = true;
                } else if (!isOpened && noteEditText.hasFocus()) {
                    Log.d("KB", "2) openKeyboard");
                    //Do two things, make the view top visible and the editText smaller
                    noteEditText.setLines(15);
                    noteEditText.requestLayout();
                    isOpened = true;
                }
            }
        }
    });

    noteEditText.setOnClickListener(new OnClickListener() {
        @Override
        public void onClick(View v) {
            Log.d("KB", "EditText onClick");
            isOpened = false;
        }
    });

    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.requestLayout();
            }
            return false;
        }
    });
}

Java - Subclassed EditText:

    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);
    }

}

However, the one remaining issue is that if the user is scrolling the EditText, sometimes it detects it as a click rather than a scroll so the keyboard is then made visible and the layout (number of lines) is changed. I looked into the onScrollChangeListener but this requires API 23 and my current minimum is 15 - is there any way around this to tell the difference between a scroll and an actual click on the EditText?

Toby Clench
  • 403
  • 1
  • 5
  • 22
  • 1
    great and yes scroll bar property to edittext i forgot to mention last time. and for last problem you mentioned, i could suggest is to add some padding to scrollbar thumb by applying style on it with this xml property android:scrollbarStyle="YourCustomScrollBarStyle" add "YourCustomScrollBarStyle" in your styles and add a padding tag in there. that might solve the problem. because it will increase area of touch for scrollbar. – Usman Ghauri Feb 09 '17 at 07:33