Question

What I'm trying to achieve is automatically scrolling to the bottom of a scrollview when a new view is added via:

mContainerView.addView(newView);

This is the code I have currently:

bt.setOnClickListener(new View.OnClickListener() {
    @Override
    public void onClick(View view) {
        String input = et.getText().toString();
        if (input != null && input.length() > 0) {
            findViewById(android.R.id.empty).setVisibility(View.GONE);
            addItem(input);
            et.setText(null);
            ScrollToBottom();
        }
    }
});

private void ScrollToBottom() {
    mScrollView.postDelayed(new Runnable() {
        @Override
        public void run() {
            mScrollView.smoothScrollTo(0, mScrollView.getBottom());
        }
    }, 300);
}

private void addItem(String name) {
    final ViewGroup newView = (ViewGroup) LayoutInflater.from(this).inflate(
            R.layout.list_item_example, mContainerView, false);

    ((TextView) newView.findViewById(android.R.id.text1)).setText(name);

    newView.findViewById(R.id.delete_button).setOnClickListener(new View.OnClickListener() {
        @Override
        public void onClick(View view) {
            mContainerView.removeView(newView);

            if (mContainerView.getChildCount() == 0) {
                findViewById(android.R.id.empty).setVisibility(View.VISIBLE);
            }
        }
    });
    mContainerView.addView(newView);
}

The reason I'm using postDelayed is because without the delay, the new view is not drawn quick enough and I end up scrolling to the bottom minus the height of the new entry. I know this to be the case because if I drop the delay time to, for example, 100ms, the scroll will end up finishing about a third of the way down the new entry. After trial and error with different values 300ms was the number that got me the desired result.

Is there a better way of achieving this? - At present my method works but it does not seem the cleanest option.

I'm still relatively new to Android/Java programming so I;m sure I might have missed something somewhere...

I should mention I have also tried fullScroll(View.FOCUS_DOWN) also, without any change in behaviour. I swapped it out for the smoothScroll option because I preferred the smoother animation

Was it helpful?

Solution

Would a listview and listadapter be a better option?

That'd be my recommendation. In particular, ListView has a so-called "transcript mode" which can be used to automatically scroll to the bottom as you add new entries to, say, an ArrayAdapter. The big benefit over ScrollView -- besides dealing with the "transcript mode" -- is the view recycling, so a lot of updates do not chew up a lot of heap space in your app.

In a ListFragment, you would execute something like this to enable transcript mode:

getListView().setTranscriptMode(ListView.TRANSCRIPT_MODE_NORMAL);

probably (though not necessarily) from wherever you set up your ListAdapter.

If your adapter is an ArrayAdapter<SomethingFun>, you can just call add() on the ArrayAdapter to append new models, and they will automatically show up at the bottom of the ListView. In "normal" transcript mode, the user will see the new entries, unless they have scrolled up to view some history, in which case the scroll position is left alone. IOW, what you normally see in a chat-style app.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top