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

Goo*_*oey 9 android listview scrollview motionevent

我有一个ListViewScrollView显示意见,我想做到以下几点:

当用户向下滑动时,首先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;
        }
    });
Run Code Online (Sandbox Code Playgroud)

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

我也尝试添加v.getParent().requestDisallowInterceptTouchEvent(false);到语句中,但这也没有用.

我怎样才能使它工作?

Geo*_*geP 8

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

onInterceptTouchEvent(MotionEvent event)
Run Code Online (Sandbox Code Playgroud)

像这样:

@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);
}
Run Code Online (Sandbox Code Playgroud)

这样ListView,你在底部的每一次Down Touch ScrollView都会转到ListView.

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

作为一个注释,我将尝试使用一个简单的实现,使用ListViewScrollView添加的当前内容作为ListView的标题使用listView.addHeaderView(scrollViewContent).我不知道这是否符合您的需求.

编辑:

检测何时应该开始滚动ScrollView.保持一个参考ListViewScrollView.当用户向上滚动并且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;
}
Run Code Online (Sandbox Code Playgroud)

ListView中的方法listIsAtTop如下所示:

public boolean listIsAtTop()   {
    if(getChildCount() == 0) return true;
    return (getChildAt(0).getTop() == 0 && getFirstVisiblePosition() ==0);
}
Run Code Online (Sandbox Code Playgroud)