当Listview位于顶部/底部时,将动作事件传递给父Scrollview

时间:2015-09-17 13:28:31

标签: android listview scrollview motionevent

我在ListView中有ScrollView来显示评论,我想执行以下操作:

当用户向下滑动时,首先ScrollView应完全向下滚动,因为列表位于底部。一旦完全关闭,Listiew应该开始滚动。

同样,当用户向上滚动时,首先ListView(此处颠倒的顺序!)应该在ScrollView开始滚动之前向上滚动。

到目前为止,我已完成以下工作:

listView.setOnTouchListener(new View.OnTouchListener() {
        // Setting on Touch Listener for handling the touch inside ScrollView
        @Override
        public boolean onTouch(View v, MotionEvent event) {

            // If going up but the list is already at up, return false indicating we did not consume it.
            if(event.getAction() == MotionEvent.ACTION_UP) {
                if (listView.getChildCount() == 0 && listView.getChildAt(0).getTop() == 0) {
                    Log.e("Listview", "At top!");
                    return false;
                }
            }

            // Similar behaviour but when going down check if we are at the bottom.
            if( event.getAction() == MotionEvent.ACTION_DOWN) {
                if (listView.getLastVisiblePosition() == listView.getAdapter().getCount() - 1 &&
                        listView.getChildAt(listView.getChildCount() - 1).getBottom() <= listView.getHeight()) {
                    Log.e("Listview","At bottom!");
                    v.getParent().requestDisallowInterceptTouchEvent(false);
                    return false;
                }
            }
            v.getParent().requestDisallowInterceptTouchEvent(true);
            return false;
        }
    });

日志会在合适的时刻触发,但即使我返回false,ScrollView也不会移动。

我还尝试在语句中添加v.getParent().requestDisallowInterceptTouchEvent(false);,但这也不起作用。

我怎样才能让它发挥作用?

3 个答案:

答案 0 :(得分:8)

您可以创建自定义ScrollViewListView并覆盖

onInterceptTouchEvent(MotionEvent event)
像这样:

@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);
}

这样,当ListView位于ScrollView时,ListView上的每次向下触摸都将转到ListView

这只是一个草图实现,但我认为你可以通过做同样的事情来检测你何时处于ListView

的顶部

作为一个说明,我会尝试使用ScrollView,使用listView.addHeaderView(scrollViewContent)添加当前内容ScrollView作为ListView的标题使用ListView,从而尝试更轻松的实现。我不知道这是否符合您的需求。

编辑:

检测何时应开始滚动ScrollView。在ListView中保留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; } 位于顶部时,public boolean listIsAtTop() { if(getChildCount() == 0) return true; return (getChildAt(0).getTop() == 0 && getFirstVisiblePosition() ==0); } 将使用该事件。

SET XACT_ABORT ON

ListView中的listIsAtTop方法如下所示:

SET NOCOUNT ON

答案 1 :(得分:4)

您不应将ListView放在ScrollView中,但可以使用ExpandableHeightListView来达到您的要求。这将在ScrollView中创建全高Listview。无需添加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>

另一种达到要求的方法是使用标题RecyclerView

答案 2 :(得分:0)

试试这个:

  1. 首先查看是否到达了scrollview Bottom。将onScrollChanged注册到滚动视图

    @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. 检查您是否到达ListView的顶部。检查firstVisibleItem是否为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!");
                    }
                }
    
            }
        });
    
  3. 我希望这适合你。如果遇到任何问题,请告诉我。