keeping bottom element of ListView visible when keyboard appears
Asked Answered
A

3

5

I have a LinearLayout containing both a ListView and an EditText. When the On-Screen keyboard is launched by touching the EditText, the ListView resizes so that only the top few elements remain visible.

The context that the ListView is being used in has the bottom few elements being more visually relevant than the top, and so I'd like for it to resize so that the bottom remains visible, rather than the top. Any pointers?

(Incidentally, the current fix I'm using involves using smoothScrollToPosition, but the laggy scroll behaviour makes this undesirable)

Alarice answered 29/11, 2011 at 0:22 Comment(1)
Try #16134206 #9352009Indoeuropean
C
1

I just solved a similar issue this morning, and thought I'd post my result here for the benefit of future searchers. My issue was that scrolling to the bottom wasn't helping since I was calling it before the view actually changed size. The solution? Wait until it does change size by using a GlobalLayoutListener

Steps: 1) implement the following method in the activity holding the listview

public void scrollToBottom(){
    //I think this is supposed to run on the UI thread
    listView.setSelection(mAdapter.getCount() - 1);
}

2) create the following class

public class OnGlobalLayoutListenerWithScrollToBottom implements OnGlobalLayoutListener{

    private boolean scroll;
    private OnScrollToBottomListener listener;
    public interface OnScrollToBottomListener{
        public void scrollToBottom();
    }

    public OnGlobalLayoutListenerWithScrollToBottom(OnScrollToBottomListener listener){
        this.listener = listener;
    }

    @Override
    public void onGlobalLayout() {
        if(scroll){
            listener.scrollToBottom();
            scroll = false;
        }
    }

    /**
     * Lets the listener know to request a scroll to bottom the next time it is layed out
     */
    public void scrollToBottomAtNextOpportunity(){
        scroll = true;
    }

};

3) In your activity, implement the interface from this class. Then, in your activity, create an instance of this OnGlobalLayoutListener and set it as the listener for your listView

    //make sure your class implements OnGlobalLayoutListenerWithScrollToBottom.OnScrollToBottomListener
    listViewLayoutListener = new OnGlobalLayoutListenerWithScrollToBottom(this);
    listView.getViewTreeObserver().addOnGlobalLayoutListener(listViewLayoutListener);

4) In your activity, before you make changes that will affect the size of list view, such as showing and hiding other views or adding stuff to the listview, simply let the layout listener know to scroll at the next opportunity

listViewLayoutListener.scrollToBottomAtNextOpportunity();
Crag answered 3/4, 2014 at 18:45 Comment(0)
J
0

You might achieve this with setSelectionFromTop() and by overriding onSizeChanged() in a custom listview. In your layout, you should have a RelativeLayout has a parent container and place the listview above the edittext.

By creating your own listview and overriding onSizeChange(), you will be able to get the last visible item's position before the listview resizing and get its new height, in order to finally set the "previous" position of the list with an offset of its height.

How it works: Your list will place the previous last visible item at its top and you will add the pixels to scroll it at its bottom, just above your edittext.

To override the method and display it with an offset, do as follows:

@Override
protected void onSizeChanged(int w, int h, int oldw, int oldh) {
    // get last visible item's position before resizing
    int lastPosition = super.getLastVisiblePosition();
    // call the super method to resize the listview
    super.onSizeChanged(w, h, oldw, oldh);
    // after resizing, show the last visible item at the bottom of new listview's height
    super.setSelectionFromTop(lastPosition, (h - lastItemHeight));
}

lastItemHeight is a little workaround, because I didn't find how to get the last item's height before that onSizeChanged is called. Then, in the case of your listview contains many types of items (without the same height), I prefer to get the selected height when an event occurs, just before the SoftKeyboard opens up.

So in the custom listview, you have this global variable:

int lastItemHeight = 0;

And in the activity (or fragment, whatever), you update this value in OnClickListener:

edittext.setOnClickListener(new View.OnClickListener() {
    @Override
    public void onClick(View v) {
        // set a new Thread
        listview.post(new Runnable() {
            @Override
            public void run() {
                // get last visible position of items
                int lastPosition = listview.getLastVisiblePosition() - 1;
                // if the view's last child can be retrieved
                if ( listview.getChildAt(lastPosition) != null ) {
                    // update the height of the last child in custom listview
                    listview.lastItemHeight = listview.getChildAt(lastPosition).getHeight();
                }
            }
        });
    }
});

Note: there is another possible solution but you have to set android:stackFromBottom="true" on the listview, which stackes its content from the bottom. Instead, this solution here can display a specific item without forcing the content to start from the bottom, with the default listview's behaviour.

Second note: (just in case) don't forget to add android:windowSoftInputMode="adjustResize" in the manifest.

Jaymie answered 11/12, 2015 at 21:29 Comment(0)
A
-1

You should add this attribute in the manifest for your activity and pick the correct value for it (probably you will pick "adjustResize"):

<activity android:name="package.yourActivity" android:windowSoftInputMode="adjustResize"/>
Animated answered 29/11, 2011 at 0:27 Comment(1)
No, this doesn't fix the issue -- the window is already set in adjustResize mode; it's the resizing behaviour of ListView that doesn't behave as desired.Alarice

© 2022 - 2024 — McMap. All rights reserved.