1

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

Karl
  • 3,394
  • 2
  • 22
  • 31
  • "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" -- that doesn't make much sense. It's not like the size of the new entry increases one pixel at a time. "I'm still relatively new to Android/Java programming" -- what's your overall UI objective? `ScrollView` isn't evil, but it's a relatively uncommon choice, and there may be better options (e.g., `ListView` in transcript mode). – CommonsWare Jun 09 '13 at 22:46
  • I have a RelativeLayout pinned to the bottom of my Activity which has an edittext for user input and a button to 'submit' that input. Hitting the button will update the 'list' as per my code above. Would a listview and listadapter be a better option? I basically followed a tutorial and tweaked it to my needs though I have had experience with ListFragments and adapters in the past. – Karl Jun 09 '13 at 22:49

1 Answers1

1

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.

CommonsWare
  • 986,068
  • 189
  • 2,389
  • 2,491
  • Thank you. I have implemented a working solution using a custom adapter and ListView. @CommonsWare – Karl Jun 09 '13 at 23:47