0

I want to implement an activity that contains a vertical ScrollView that has several horizontal RecyceViews as children!

but sometimes I faced to a strange touch interrupts from inner RecycleViews, when I try to scroll in the vertical direction and my start point of touch is in inside of an item( of RecycleView) scrolling of ScrollView doesn't work correctly and it doesn't scroll in Y direction!

I try to implement my own ScrollView and RecycleView To handle touch actions but the problem still exists!

you can watch what really happens in this video: video of my applications problem

MyScrollView:

public class MyScrollView extends ScrollView {
    private GestureDetector mGestureDetector;

    public MyScrollView(Context context, AttributeSet attrs) {
        super(context, attrs);
        mGestureDetector = new GestureDetector(context, new YScrollDetector());
        setFadingEdgeLength(0);
    }

    @Override
    public boolean onInterceptTouchEvent(MotionEvent ev) {
        return super.onInterceptTouchEvent(ev) && mGestureDetector.onTouchEvent(ev);
    }

    @Override
    public boolean canScrollVertically(int direction) {
        return true;
    }


    @Override
    public boolean canScrollHorizontally(int direction) {
        return false;
    }

    // Return false if we're scrolling in the x direction
    class YScrollDetector extends GestureDetector.SimpleOnGestureListener {
        @Override
        public boolean onScroll(MotionEvent e1, MotionEvent e2, float distanceX, float distanceY) {
            boolean result=Math.abs(distanceY) > Math.abs(distanceX);
            Log.d("ADAPTER MYSCR G = ",result+"");
            return result;
        }
    }

}

MyRecycleView:

public class MyRecycleView extends RecyclerView {
    private GestureDetector mGestureDetector;

    public MyRecycleView(Context context) {
        super(context);
        mGestureDetector = new GestureDetector(context, new MyRecycleView.XScrollDetector());
    }

    public MyRecycleView(Context context, @Nullable AttributeSet attrs) {
        super(context, attrs);
        mGestureDetector = new GestureDetector(context, new MyRecycleView.XScrollDetector());
    }

    public MyRecycleView(Context context, @Nullable AttributeSet attrs, int defStyle) {
        super(context, attrs, defStyle);
        mGestureDetector = new GestureDetector(context, new MyRecycleView.XScrollDetector());
    }


    @Override
    public boolean onInterceptTouchEvent(MotionEvent e) {
        boolean result=super.onInterceptTouchEvent(e) && mGestureDetector.onTouchEvent(e);
        if(!result) {
            Log.d("ADAPTER MYREC G = ",result+"");
            View parent=((View) getParent());

            while (parent!=null){
                if(parent.getClass().getName().equals("class com.android.internal.policy.DecorView"))
                    break;
                if(parent instanceof MyScrollView) {
                    Log.d("MY SCROLL VIEW","FOUND AS PARENT!");
                    ((MyScrollView) parent).requestDisallowInterceptTouchEvent(false);
                    break;
                }
                parent= (View) parent.getParent();
            }

            this.stopScroll();
        }
        return result;
    }

    @Override
    public boolean canScrollHorizontally(int direction) {
        return true;
    }


    @Override
    public boolean canScrollVertically(int direction) {
        return false;
    }

    // Return false if we're scrolling in the y direction
    class XScrollDetector extends GestureDetector.SimpleOnGestureListener {
        @Override
        public boolean onScroll(MotionEvent e1, MotionEvent e2, float distanceX, float distanceY) {
            boolean result=Math.abs(distanceY) < Math.abs(distanceX);
            return result;
        }
    }
}

and here is my RecycleView items adapter xml:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/lib/io.github.makbn.graphics"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:layout_gravity="center"
    android:layout_margin="2dp"
    android:background="@android:color/transparent"
    android:gravity="center"
    android:orientation="vertical">

    <android.support.v7.widget.CardView
        android:id="@+id/graphics_card_container"
        android:layout_width="115dp"
        android:layout_height="180dp"
        android:layout_marginBottom="3dp"
        android:layout_marginLeft="4dp"
        android:layout_marginRight="4dp"
        android:layout_marginTop="1dp"
        android:foreground="?android:attr/selectableItemBackground"
        app:cardBackgroundColor="#fff"
        android:clickable="true"
        android:focusableInTouchMode="false"
        android:filterTouchesWhenObscured="true"
        android:focusable="false"
        app:cardElevation="2dp"
        app:cardPreventCornerOverlap="true">
        <LinearLayout
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:gravity="center"
            android:orientation="vertical">
            <RelativeLayout
                android:id="@+id/layout_foodview_container"
                android:layout_width="match_parent"

                android:layout_height="wrap_content">

                <ImageView
                    android:id="@+id/graphics_img_icon"
                    android:layout_width="match_parent"
                    android:layout_height="80dp"
                    android:layout_gravity="center"
                    android:background="#00000000"
                    android:scaleType="centerCrop" />

                <RatingBar
                    style="@style/MyRatingBar_Style"
                    android:id="@+id/rating"
                    android:layout_width="match_parent"
                    android:layout_height="20dp"
                    android:layout_alignBottom="@+id/graphics_img_icon"
                    android:layout_centerInParent="true"
                    android:layout_gravity="center_horizontal"
                    android:isIndicator="true"
                    android:background="@color/white_overlay"
                    android:numStars="5" />
            </RelativeLayout>

            <TextView
                android:id="@+id/txt_name"
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:layout_below="@+id/img_logo"
                android:layout_gravity="center"
                android:layout_margin="3dp"
                android:ellipsize="end"
                android:gravity="center"
                android:lines="2"
                android:maxLines="2"
                android:padding="2dp"
                android:text="نام محصول"
                android:textSize="12sp" />

            <LinearLayout
                android:layout_width="match_parent"
                android:layout_height="0dp"
                android:layout_weight="1"></LinearLayout>

            <TextView
                android:id="@+id/txt_price"
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:layout_gravity="bottom"
                android:background="@color/colorAccent"
                android:gravity="center_horizontal"
                android:padding="3dp"
                android:text="۷۵۰۰ ت"
                android:textColor="#fff"
                android:textSize="12sp" />
        </LinearLayout>
    </android.support.v7.widget.CardView>
</LinearLayout>

And in my activty I find my MyScrollView and create several instance of MyRecycleView and add to it!

  • instead of using scrollview... why can't you try with recyclerview itself – Jeevanandhan Aug 17 '17 at 11:00
  • @Jeevanandhan because my main activity is dynamic and different views can add to scroll view handled by server and doing this with recycleview is so complicated and hard – Mehdi Akbarian Rastaghi Aug 17 '17 at 11:42
  • :: I don't think recyclerview will be complex as of scrollview, because in recyclerview we can use getItemViewType method in adapter. Some how to load data dynamically in scrollview you might be doing some validation to populate data. do that in getItemViewType method in recyclerview adapter and create seperate viewholder, by this way you can achieve code reusability also. for example I will share you a link, I won't give you exact solution but a approach which might help you :) https://stackoverflow.com/a/44470106/1501864 – Jeevanandhan Aug 17 '17 at 11:56

1 Answers1

0

If i have understood your issue correctly then you don't need to do all this. Use NestedScrollView instead of scrollview.

Suggestion: I watched your video, You can also use nested recyclerview to make your UI completely dynamic. RecyclerView is very powerful with it's ViewHolders. You can add Horizontal RecyclerView in Item of the parent recyclerview then initialise inner recyclerViews with adapters in the onBind method of the parent.