Search code examples
androidtouch-eventandroid-scrollview

ScrollView's child cannot get ACTION_MOVE and ACTION_UP event when touch child and scroll vertically


I have some views in ScrollView. The problem is when I touch the child view and scroll it vertically, the child view can only get ACTION_DOWN and ACTION_CANCEL event. The ACTION_MOVE and ACTION_UP event is missed.
If I touch the child view and scroll it horizontally, the child view can get all the touch event just as expected.
Here is my code:
xml file:

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

    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:orientation="vertical">

        <TextView
            android:id="@+id/sv_test_tv"
            android:layout_width="match_parent"
            android:layout_height="100dp"
            android:gravity="center"
            android:text="This is some text."
            android:textSize="30sp" />

        <View
            android:layout_width="match_parent"
            android:layout_height="300dp"
            android:background="#faa" />

        <View
            android:layout_width="match_parent"
            android:layout_height="300dp"
            android:background="#faf" />

    </LinearLayout>

</ScrollView>

java code:

@Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.sv_test);

        TextView tv = (TextView) findViewById(R.id.sv_test_tv);
        tv.setOnTouchListener(new View.OnTouchListener() {
            @Override
            public boolean onTouch(View v, MotionEvent event) {
                LogUtils.v("ScrollViewTest", "onTouch:" + getType(event.getAction()));

                return true;
            }
        });

    }

    private String getType(int type) {
        switch (type) {
            case MotionEvent.ACTION_DOWN: {
                return "ACTION_DOWN";
            }

            case MotionEvent.ACTION_MOVE: {
                return "ACTION_MOVE";
            }

            case MotionEvent.ACTION_UP: {
                return "ACTION_UP";
            }
        }

        return "other:" + type;
    }

Anyone can help me? Thanks a lot.


Solution

  • You can add custom scrollview to your layout. Create your custom scrollView and use it in your layout.

    public class VerticalScrollview extends ScrollView{
    
        public VerticalScrollview(Context context) {
            super(context);
        }
    
        public VerticalScrollview(Context context, AttributeSet attrs) {
            super(context, attrs);
        }
    
        public VerticalScrollview(Context context, AttributeSet attrs, int defStyle) {
            super(context, attrs, defStyle);
        }
    
        @Override
        public boolean onInterceptTouchEvent(MotionEvent ev) {
            final int action = ev.getAction();
            switch (action)
            {
                case MotionEvent.ACTION_DOWN:
                    super.onTouchEvent(ev);
                    break;
    
                case MotionEvent.ACTION_MOVE:
                    return false; // redirect MotionEvents to ourself
    
                case MotionEvent.ACTION_CANCEL:
                    super.onTouchEvent(ev);
                    break;
    
                case MotionEvent.ACTION_UP:
                    return false;
    
                default:  break;
            }
    
            return false;
        }
    
        @Override
        public boolean onTouchEvent(MotionEvent ev) {
            super.onTouchEvent(ev);
            //Log.i("VerticalScrollview", "onTouchEvent. action: " + ev.getAction() );
            return true;
        }
    }
    

    Add <packagename..VerticalScrollview /> in place of ScrollView.