Search code examples
androidandroid-scrollview

scrollTo() for horizontalScrollView not working


I inflate another layout to appear below some view in my current layout.

This is done like this:

       LayoutInflater vi = (LayoutInflater) getActivity().getApplicationContext()
            .getSystemService(Context.LAYOUT_INFLATER_SERVICE);
    View rootView = vi.inflate(R.layout.horizontal_scroll_view, null);

    horizontalScrollView = (HorizontalScrollView) rootView.findViewById(R.id.hsv_suggestions_scroll_view);
    LinearLayout suggestionsContainer = (LinearLayout) horizontalScrollView.findViewById(R.id.ll_suggestions_container);

and I can confirm that it appears in the right place since I add some Views in it after a while and they all appear.

The layout I inflate is :

<HorizontalScrollView xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/hsv_suggestions_scroll_view"
android:scrollbars="none" android:layout_gravity="center_horizontal"
android:paddingTop="16dp" android:fillViewport="true"
android:layout_width="match_parent" android:layout_height="wrap_content">

    <LinearLayout
      android:id="@+id/ll_suggestions_container"
      android:gravity="center_horizontal"    android:orientation="horizontal"
      android:layout_width="wrap_content" android:layout_height="wrap_content">

</LinearLayout>

just a HorizontalScrollView with a LinearLayout as a child. The Views I add later are all of them TextViews.

Now after a user action (write some text on an editText) I'm trying to scroll to that View and highlight it. Highlight works. What does not work is scroll.

I have tried :

 horizontalScrollView.postDelayed(new Runnable() {
   @Override
   public void run() {

   horizontalScrollView.smoothScrollTo(scrollTo, 0);
   }
}, 300);

where variable scrollTo is what I get when I apply getLeft() to the View I wanna scroll to. I can confirm that it takes various values.

Anyone can help me with that ?


Solution

  • Switch to using a RecyclerView with a LinearLayoutManager with orientation set to Horizontal. Like this:

    scroll_view.xml

    <android.support.v7.widget.RecyclerView xmlns:android="http://schemas.android.com/apk/res/android"
        xmlns:app="http://schemas.android.com/apk/res-auto"
        android:id="@+id/scrollView"
        android:scrollbars="none"
        android:layout_gravity="center_horizontal"
        android:paddingTop="16dp"
        android:fillViewport="true"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        app:layoutManager="android.support.v7.widget.LinearLayoutManager"
        android:orientation="horizontal">
        <LinearLayout
            android:id="@+id/scrollContainer"
            android:gravity="center_horizontal"
            android:orientation="horizontal"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content" />
    </android.support.v7.widget.RecyclerView>
    

    Note: the layoutManager tag is required here for the layout to inflate. After it's inflated, we're going to set it programatically as well because otherwise we'll get an exception because the RecyclerView basically disposes of it before it's done with it.

    OptionAdapter.java

    public class OptionAdapter extends RecyclerView.Adapter<OptionAdapter.OptionHolder> {
    
        private Context context;
        private LayoutInflater inflater;
    
        private ArrayList<String> options;
    
        public OptionAdapter(Context context) {
            this.context = context;
            this.inflater = LayoutInflater.from(context);
    
            options = new ArrayList<>();
        }
    
        @Override
        public OptionHolder onCreateViewHolder(ViewGroup parent, int viewType) {
            return new OptionHolder(inflater.inflate(R.layout.textview, parent, false));
        }
    
        @Override
        public void onBindViewHolder(OptionHolder holder, int position) {
            String option = options.get(position);
    
            ((TextView) holder.itemView).setText(option);
        }
    
        @Override
        public int getItemCount() {
            return options != null ? options.size() : 0;
        }
    
        public ArrayList<String> getOptions() {
            return options;
        }
    
        public void addOption(String option, Integer index) {
            if (index != null && index <= options.size()) {
                options.add(index, option);
            } else {
                options.add(option);
            }
    
            notifyDataSetChanged();
        }
    
        public class OptionHolder extends RecyclerView.ViewHolder {
    
            public OptionHolder(View itemView) {
                super(itemView);
            }
        }
    }
    

    text_view.xml

    <?xml version="1.0" encoding="utf-8"?>
    <TextView xmlns:android="http://schemas.android.com/apk/res/android"
        android:layout_marginLeft="8dp"
        android:layout_marginRight="8dp"
        android:orientation="vertical"
        android:layout_width="wrap_content"
        android:layout_height="match_parent" />
    

    Setting everything up

    final LayoutInflater inflater = LayoutInflater.from(this);
    final RecyclerView scrollView = (RecyclerView) inflater.inflate(R.layout.scroll_view, container, false);
    scrollView.setLayoutManager(new LinearLayoutManager(this, LinearLayoutManager.HORIZONTAL, false));
    
    final OptionAdapter adapter = new OptionAdapter(this);
    scrollView.setAdapter(adapter);
    

    container here is whatever view is going to be holding the RecyclerView. In my code, I've got it in a LinearLayout.

    Adding a view to the list

    adapter.addOption("The Added One", null);

    Or if you want to add it to a specific position in the list.

    adapter.addOption("The Added One", position);

    Scrolling to a specific position

    scrollView.smoothScrollToPosition(position);

    Scrolling to a specific item in the list

    scrollView.smoothScrollToPosition(adapter.getOptions().indexOf("ItemText"));

    Hope it works for you!