Pass motion event to parent Scrollview when Listview at top/bottom

和自甴很熟 提交于 2019-11-29 06:38:51

You can create a custom ScrollView and ListView and override

onInterceptTouchEvent(MotionEvent event)

like this:

@Override
public boolean onInterceptTouchEvent(MotionEvent event) {
    View view = (View) getChildAt(getChildCount()-1);
    int diff = (view.getBottom()-(getHeight()+getScrollY()));

    if( event.getAction() == MotionEvent.ACTION_DOWN) {
        if (diff ==0) {
            return false;
        }
    }

    return super.onInterceptTouchEvent(event);
}

This way every Down Touch on the ListView while you are at the bottom of ScrollView will go to the ListView.

This is just a sketch implementation but I think you could get started from this by doing the same thing to detect when you are at the top of the ListView

As a note I would try an easier implementation by using just a ListView with the current content of you ScrollView added as the header of ListView by using listView.addHeaderView(scrollViewContent). I don't know if this fits your needs.

EDIT:

Detecting when should start scrolling the ScrollView. Keeping a reference of ListView in the ScrollView. When the user is scrolling up and the the ListView is at the top let the event be consumed by the ScrollView.

private void init(){
    ViewConfiguration vc = ViewConfiguration.get(getContext());
    mTouchSlop = vc.getScaledTouchSlop();
}

@Override
public boolean onInterceptTouchEvent(MotionEvent event) {
    final int action = MotionEventCompat.getActionMasked(event);

    switch (action) {
        case MotionEvent.ACTION_DOWN:{
            yPrec = event.getY();
        }
        case MotionEvent.ACTION_MOVE: {
            final float dy = event.getY() - yPrec;

            if (dy > mTouchSlop) {
                // Start scrolling!
                mIsScrolling = true;
            }
            break;
        }
    }

    if (action == MotionEvent.ACTION_CANCEL || action == MotionEvent.ACTION_UP) {
        mIsScrolling = false;
    }

    // Calculate the scrolldiff
    View view = (View) getChildAt(getChildCount()-1);
    int diff = (view.getBottom()-(getHeight()+getScrollY()));

        if ((!mIsScrolling || !listViewReference.listIsAtTop()) && diff == 0) {
            if (event.getAction() == MotionEvent.ACTION_MOVE) {
                return false;
            }
    }

    return super.onInterceptTouchEvent(event);
}

@Override
public boolean onTouchEvent(MotionEvent ev) {
    final int action = MotionEventCompat.getActionMasked(ev);
    if (action == MotionEvent.ACTION_CANCEL || action == MotionEvent.ACTION_UP) {
        mIsScrolling = false;
    }
    return super.onTouchEvent(ev);
}


public void setListViewReference(MyListView listViewReference) {
    this.listViewReference = listViewReference;
}

The method listIsAtTop in ListView looks like this :

public boolean listIsAtTop()   {
    if(getChildCount() == 0) return true;
    return (getChildAt(0).getTop() == 0 && getFirstVisiblePosition() ==0);
}

You should not put ListView inside ScrollView, but you can achieve your requirement by using ExpandableHeightListView. This will make full height Listview inside ScrollView. No need add TouchListener.

<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">

        <RelativeLayout
            android:layout_width="match_parent"
            android:layout_height="wrap_content" >
             <!-- your content -->
        </RelativeLayout>

        <my.widget.ExpandableHeightListView
            android:layout_width="match_parent"
            android:layout_height="wrap_content" />
    </LinearLayout>
</ScrollView>

And another way to achieve your requirement is RecyclerView with header.

Hradesh Kumar

Try This:

  1. First find if you reached at scrollview Bottom. Register the onScrollChanged to your Scroll view

    @Override
    protected void onScrollChanged(int l, int t, int oldl, int oldt) 
    {
        // Grab the last child placed in the ScrollView, we need it to determinate the bottom position.
        View view = (View) getChildAt(getChildCount()-1);
    
        // Calculate the scrolldiff
        int diff = (view.getBottom()-(getHeight()+getScrollY()));
    
        // if diff is zero, then the bottom has been reached
        if( diff == 0 )
        {
            // notify that we have reached the bottom
            // Add code here to start scrolling the ListView
            Log.d(ScrollTest.LOG_TAG, "MyScrollView: Bottom has been reached" );
        }
    
        super.onScrollChanged(l, t, oldl, oldt);
    }
    
  2. Check if you reach at the Top of ListView. Check if firstVisibleItem is 0:-

    tableListView.setOnScrollListener(new OnScrollListener() {
    
            public void onScrollStateChanged(AbsListView view, int scrollState) {
    
            }
    
            public void onScroll(AbsListView view, int firstVisibleItem,
                    int visibleItemCount, int totalItemCount) {
                if (visibleItemCount == 0)
                // you have reached at top of lustView
                {
                    java.lang.System.out.println("you have reached at top of lustView!");
                }
                else {
                    if ((firstVisibleItem + visibleItemCount) == totalItemCount) {
                        // put your stuff here
                        java.lang.System.out.println("end of the line reached!");
                    }
                }
    
            }
        });
    

I hope this works for you. If face any issues, please let me know.

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!