1

I have designed this layout layout in which i have a NestdScrollView which contains 3 RecycleViews. On each RecycleView item click appears another NestedRecycleView appears with is inside ScrollView of height 200dp. NestedRecycleView scroll does not work. In the image there are more than 4 "list items" but only 4 are shown, it is not scrollable. When I scroll the parent NestdScrollView scrolls.

Someone commented about this being bad design, if anyone has a idea how to approach this kindly share your ideas also.

enter image description here RecycleView Adapter

  public class MyRecyclerViewAdapter extends RecyclerView.Adapter<MyRecyclerViewAdapter.ViewHolder> {

        private List<String> mData;
        private LayoutInflater mInflater;
        private ItemClickListener mClickListener;
        private Context context;

        // data is passed into the constructor
        MyRecyclerViewAdapter(Context context, List<String> data) {
            this.mInflater = LayoutInflater.from(context);
            this.mData = data;
            this.context=context;
        }

        // inflates the row layout from xml when needed
        @Override
        public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
            View view = mInflater.inflate(R.layout.list_item_text, parent, false);
            return new ViewHolder(view);
        }

        // binds the data to the TextView in each row
        @Override
        public void onBindViewHolder(ViewHolder holder, int position) {
            String animal = mData.get(position);
            holder.myTextView.setText(animal);
        }

        // total number of rows
        @Override
        public int getItemCount() {
            return mData.size();
        }


        // stores and recycles views as they are scrolled off screen
        public class ViewHolder extends RecyclerView.ViewHolder implements View.OnClickListener {
            TextView myTextView;
            RecyclerView recyclerViewNested;
            ScrollView nestedScrollViewRecycleView;

            ViewHolder(View itemView) {
                super(itemView);
                myTextView = itemView.findViewById(R.id.text_view);
                recyclerViewNested = itemView.findViewById(R.id.recycle_view_nested);
                nestedScrollViewRecycleView= itemView.findViewById(R.id.nested_scrollview_in_recycleview);
                myTextView.setOnClickListener(new View.OnClickListener() {
                    @Override
                    public void onClick(View view) {
                        ArrayList<String> list12 = new ArrayList<String>(
                                Arrays.asList("list item", "list item", "list item","list item","list item", "list item", "list item","list item","list item", "list item", "list item","list item","list item", "list item", "list item","list item","list item", "list item", "list item","list item"));
                        nestedScrollViewRecycleView.setVisibility(View.VISIBLE);

                        MyRecyclerViewAdapter adapter = new MyRecyclerViewAdapter(context, list12);
                        LinearLayoutManager layoutManager = new LinearLayoutManager(context, recyclerViewNested.VERTICAL, false);
                        recyclerViewNested.setLayoutManager(layoutManager);
                        recyclerViewNested.setAdapter(adapter);


                    }
                });
                //itemView.setOnClickListener(this);
            }

            @Override
            public void onClick(View view) {
                if (mClickListener != null) mClickListener.onItemClick(view, getAdapterPosition());
            }
        }

        // convenience method for getting data at click position
        String getItem(int id) {
            return mData.get(id);
        }

        // allows clicks events to be caught
        void setClickListener(ItemClickListener itemClickListener) {
            this.mClickListener = itemClickListener;
        }

        // parent activity will implement this method to respond to click events
        public interface ItemClickListener {
            void onItemClick(View view, int position);
        }
    }

MainActivity

public class MainActivity extends AppCompatActivity {

    public static final int SWIPE_THRESHOLD = 100;
    public static final int SWIPE_VELOCITY_THRESHOLD = 100;
    private static final String TAG = "MainActivity";

    ArrayList<String> list2;
    NestedScrollView NestedScroll1;
    ConstraintLayout constraintLayout;
    RecyclerView recyclerView1;
    //vars

 private boolean mSwiping = false;
    private float mDownX = 0;
    private float xCoOrdinate;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        recyclerView1 = findViewById(R.id.firstColumn);
        RecyclerView recyclerView2 = findViewById(R.id.secondColumn);
        RecyclerView recyclerView3 = findViewById(R.id.thirdColumn);
        NestedScroll1 = findViewById(R.id.scrollview_nested);

        ArrayList<String> list12 = new ArrayList<String>(
                Arrays.asList("A", "column1", "test1", "1", "2", "3", "1", "2", "3", "1", "2", "3", "1", "2", "3", "1", "2", "3", "2", "3", "1", "2", "3", "1", "2", "3", "1", "2", "3", "1", "2", "3"));
        list2 = new ArrayList<String>(
                Arrays.asList("B", "column3", "test3", "111", "211", "311", "111", "211", "311", "111", "211", "311", "111", "211", "311", "111", "211", "311", "311", "111", "211", "311", "111", "211", "311", "111", "211", "311"));


        // set up the RecyclerView
        MyRecyclerViewAdapter adapter = new MyRecyclerViewAdapter(this, list12);

        configRecyclerView(recyclerView1, adapter);
        configRecyclerView(recyclerView2, adapter);
        configRecyclerView(recyclerView3, adapter);


    recyclerView2.addOnItemTouchListener(getOnItemTouchListener());
    recyclerView3.addOnItemTouchListener(getOnItemTouchListener());

    }

    private void configRecyclerView(RecyclerView recyclerView, MyRecyclerViewAdapter adapter) {
        LinearLayoutManager layoutManager = new LinearLayoutManager(getApplicationContext(), recyclerView.VERTICAL, false);
        recyclerView.setLayoutManager(layoutManager);
        recyclerView.setAdapter(adapter);
    }



private RecyclerView.OnItemTouchListener getOnItemTouchListener() {
        return new RecyclerView.OnItemTouchListener() {
            @SuppressLint("LongLogTag")
            @Override
            public boolean onInterceptTouchEvent(RecyclerView rv, MotionEvent ev) {
                Log.d("TableView OnswipeTouchListener: ", " recycleViewOdds item onInterceptTouchEvent");

                switch (ev.getAction()) {
                    case MotionEvent.ACTION_DOWN:
                        mDownX = ev.getX();
                        mSwiping = false;

                        //coordinate for moving
                        xCoOrdinate = constraintLayout.getX() - ev.getRawX();

                        break;
                    case MotionEvent.ACTION_CANCEL:
                        //return true;
                    case MotionEvent.ACTION_UP:
                        if (mSwiping) {

                            /// this return true block touch event
                            Log.d("TableView OnswipeTouchListener:", "Recycle view odds OnItemTouchListener: you swiped!");
                            return true;
                        }
                        break;
                    case MotionEvent.ACTION_MOVE:
                        float xMove = ev.getX();
                        float xDelta = Math.abs(xMove - mDownX);

                        if (xDelta > 5) {
                            mSwiping = true;
                            // this one also
                            return true;
                        }
                        break;
                }

                return false;
            }

            private Rect rect;

            @SuppressLint("LongLogTag")
            @Override
            public void onTouchEvent(RecyclerView rv, MotionEvent event) {

                int limitLeft = constraintLayout.getLeft();
                int limitRight = constraintLayout.getRight();


                switch (event.getAction()) {
                    case MotionEvent.ACTION_DOWN:

                        break;
                    case MotionEvent.ACTION_MOVE:
                        //   Log.d("OnSwipeTouchListener Class", "recycleViewOdds action move");

                        //Restrict move to constraintLayout width
                        // Log.d("Recycleview TouchListener windowwidth: ", limitLeft + ", " + limitRight);

                        float range = event.getRawX() + xCoOrdinate;

                        if (Math.abs(range) > limitLeft - 350 && Math.abs(range) < limitRight - 250) {
                            //constraintLayout.scrollTo((int) (event.getRawX() + xCoOrdinate),0);
                            constraintLayout.animate().x(event.getRawX() + xCoOrdinate).setDuration(0).start();
                            constraintLayout.setAlpha(0.7f);
                        }

                        break;
                    case MotionEvent.ACTION_UP:
                        Log.d("TableView OnswipeTouchListener:", "recycleViewOdds action up");
                        constraintLayout.animate().alpha(1).translationX(0).translationY(0);

                        break;

                    case MotionEvent.ACTION_CANCEL:
                        constraintLayout.animate().alpha(1).translationX(0).translationY(0);

                        Log.d("TableView OnswipeTouchListener:", "recycleViewOdds action cancel");
                        break;
                }
            }


            @SuppressLint("LongLogTag")
            @Override
            public void onRequestDisallowInterceptTouchEvent(boolean disallowIntercept) {
                Log.e("TableView OnswipeTouchListener:", "recycleViewOdds item touch intercept disallow request");

            }
        };
    }

}

activity_main.xml

<androidx.core.widget.NestedScrollView
    android:id="@+id/scrollview_nested"
    android:layout_width="match_parent"
    android:layout_height="0dp"
    android:text="Hello World!"
    app:layout_constraintBottom_toBottomOf="parent"
    app:layout_constraintLeft_toLeftOf="parent"
    app:layout_constraintRight_toRightOf="parent"
    app:layout_constraintTop_toTopOf="parent">

    <androidx.constraintlayout.widget.ConstraintLayout
        android:layout_width="match_parent"
        android:layout_height="match_parent">

        <androidx.recyclerview.widget.RecyclerView
            android:id="@+id/firstColumn"
            android:layout_width="0dp"
            android:layout_height="match_parent"
            android:layout_centerHorizontal="true"
            android:nestedScrollingEnabled="false"
            app:layout_constraintEnd_toStartOf="@id/secondColumn"
            app:layout_constraintStart_toStartOf="parent"
            app:layout_constraintTop_toTopOf="parent" />


        <androidx.recyclerview.widget.RecyclerView
            android:id="@+id/secondColumn"
            android:layout_width="0dp"
            android:layout_height="wrap_content"
            android:layout_marginLeft="16dp"
            app:layout_constraintEnd_toStartOf="@id/thirdColumn"
            app:layout_constraintLeft_toRightOf="@id/firstColumn"
            app:layout_constraintTop_toTopOf="parent" />

        <androidx.recyclerview.widget.RecyclerView
            android:id="@+id/thirdColumn"
            android:layout_width="0dp"
            android:layout_height="wrap_content"
            android:layout_marginLeft="16dp"
            app:layout_constraintEnd_toEndOf="parent"
            app:layout_constraintLeft_toRightOf="@id/secondColumn"
            app:layout_constraintTop_toTopOf="parent" />
    </androidx.constraintlayout.widget.ConstraintLayout>
</androidx.core.widget.NestedScrollView>

list_item_text.xml

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

    <TextView
        android:id="@+id/text_view"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:textSize="20sp"
        android:layout_marginBottom="8dp"/>
    <ScrollView
        android:id="@+id/nested_scrollview_in_recycleview"
        android:layout_width="match_parent"
        android:visibility="gone"
        android:background="@color/colorAccent"
        android:layout_height="200dp">
        <androidx.recyclerview.widget.RecyclerView
            android:id="@+id/recycle_view_nested"
            android:layout_width="match_parent"
            android:nestedScrollingEnabled="false"
            android:layout_height="wrap_content"/>

    </ScrollView>

</LinearLayout>
Amir Dora.
  • 2,831
  • 4
  • 40
  • 61
  • 1st of all, why are the recycler views placed inside a nested scroll view? – a fair player Apr 09 '20 at 19:11
  • And you may consider using an expandable recycler view to have the nested list effect. – a fair player Apr 09 '20 at 19:14
  • i placed 3 main recycleViews inside nestedScrollview so that they scroll together. Then for NestedRecycleView i put it inside scrollview to give it 200dp fixed height. @afairplayer – Amir Dora. Apr 09 '20 at 19:32
  • thanks for your suggestion but the reason i did not use expandable recycleview is that i want my nestedRecycleview to have a certain height, i don't want it to occupy much of screen when expanded as it is a huge list. Hence i put it inside scrollview this way i can give it a fixed height. @afairplayer – Amir Dora. Apr 09 '20 at 20:02
  • Take a step back, and look at what you want to accomplish, perhaps you will come up with a better more organic way to approuch it. This thing that you are doing, is bad design. – Thalis Vilela Apr 09 '20 at 21:39
  • thanks @ThalisVilela for your comment, if you have any suggestion regarding design kindly share. – Amir Dora. Apr 10 '20 at 15:14
  • I can't know the best design approuch, as i don't know what are the project constraints. But just as an example: Perhaps, you turn the "columns" into Tabs, and then, for the item you have nested data, you can create a "details" page. – Thalis Vilela Apr 10 '20 at 17:04
  • yea unfortunately the design should be the same. I have three columns in total, the left column is constant, rightmost columns are repopulated on swipe left or right. Basically there are 8 to 10 columns which i show to user on user swipe gesture. I have tried viewpager also it was very slow. This approach is much faster, only problem with ontouch listener. – Amir Dora. Apr 11 '20 at 15:55
  • My First suggestion for performance optimization would be to use setRecyclerViewPool method for all the vertical recycler views to share the same pool of views, to prevent the overhead of new views creation for new recycler view coming into the picture from right swipe gesture, As All recyclers' items are of same type Use below link for the reference https://stackoverflow.com/a/47358401/3497972 – akashzincle Apr 11 '20 at 19:18

3 Answers3

1

My suggestion would be in "list_item_text", In this, you have a scroll view and recycler view encapsulated, I am assuming these items will be very less in number around 5-10 and mostly will be visible on the screen, So there won't be any performance issue If we directly add LinearLayout in a parent layout dynamically by iterating a loop, only con of this approach will be that the views which are out of the screen, will be loaded into memory (which is not in recycler view), But considering your number of items, This is accepted, most of your items will be visible on the screen, And obviously It will save an extra overhead of Recyclerview population, rendering and all. Hope It will solve your touch issue.

akashzincle
  • 1,108
  • 6
  • 15
  • Thanks for suggestio but how does this approach fix scrolling issue, as my layout height is 200dp, i guess the user will still have to scroll through the list to see all the items. There are about 100 items to be displayed inside scrollView. – Amir Dora. Apr 11 '20 at 20:51
  • 1
    ok, I feel, onIterceptTouchEvent() overriding in the scroll view or recycler view might help you, Check below link for the implementation http://neevek.net/posts/2013/10/13/implementing-onInterceptTouchEvent-and-onTouchEvent-for-ViewGroup.html – akashzincle Apr 11 '20 at 21:03
  • Thanks @akashzincle i used onIterceptTouchEvent() and set getparent().disallowTouchIntercept(true) to disallow parent to get touch listener, but the parent also needs to process touch listener as when the parent recycleview is swiped left right, it animates on user touch. So when nestedRecycleview grabs touch animation doesn't work for parent – Amir Dora. Apr 11 '20 at 21:17
  • so @akashzincle i finally was able to figure out the issue, your idea of overriding the onIterceptTouchEvent() helped achieve the result, i override onIterceptTouchEvent() of those recycleviews i want to intercept touch event. So i am accepting your answer and i added a sample code to your answer, it might hep other users. – Amir Dora. Apr 16 '20 at 17:37
  • 1
    Awesome! good to know you cracked this :) thanks for adding the code, will check it – akashzincle Apr 16 '20 at 17:49
1

Add recyclerView.setNestedScrollingEnabled(false); to all RecyclerViews and check if that solves the problem with scrolling.

Sina
  • 2,683
  • 1
  • 13
  • 25
  • Thanks @Sina. I tried adding setNestedScrollingEnabled(false) to nested recycleviews also, still not scrolling. I guess this has to do something with touch listener on android, from what i understand there is conflict between two recycleview ontouch Listeners. – Amir Dora. Apr 14 '20 at 20:26
  • @Amir I'll check more. – Sina Apr 15 '20 at 05:31
  • Can you try setting the recyclerView's layout_height to wrap_content so it is as tall as its children, and won't need to scroll. – Avramo Feb 14 '22 at 14:40
0

activity_main.xml
Please add android:nestedScrollingEnabled="true" in all RecyclerView Tags...


list_item_text.xml
Please add android:fillViewport="true" in ScrollView Tag
then change android:layout_height="wrap_content" to android:layout_height="0dp" in RecyclerView Tag...
Jaimil Patel
  • 1,301
  • 6
  • 13