代码之家  ›  专栏  ›  技术社区  ›  Gooey

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

  •  9
  • Gooey  · 技术社区  · 9 年前

    我有一个 ListView 在一个 ScrollView 显示评论,我想做以下工作:

    当用户向下滑动时,首先 卷轴视图 应该完全向下滚动,因为列表位于底部。一旦完全放下 Listiew 应该开始滚动。

    类似地,当用户向上滚动时,首先 列表视图 (此处顺序颠倒!)应该向上滚动,在 卷轴视图 开始滚动。

    到目前为止,我做了以下工作:

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

    日志在正确的时刻触发,然而 卷轴视图 即使我返回错误,也不会移动。

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

    我怎样才能让它工作?

    3 回复  |  直到 9 年前
        1
  •  8
  •   GeorgeP    9 年前

    您可以创建自定义 ScrollView ListView 和覆盖

    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的标头 listView.addHeaderView(scrollViewContent) 我不知道这是否符合你的需要。

    编辑:

    检测何时开始滚动 卷轴视图 .保留以下内容的参考 列表视图 卷轴视图 。当用户向上滚动时 列表视图 位于顶部,让事件由 卷轴视图 .

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

    ListView中的listIsAtTop方法如下所示:

    public boolean listIsAtTop()   {
        if(getChildCount() == 0) return true;
        return (getChildAt(0).getTop() == 0 && getFirstVisiblePosition() ==0);
    }
    
        2
  •  4
  •   Kishan Vaghela    9 年前

    您不应该将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 带收割台。

        3
  •  0
  •   Alex Feinman    9 年前

    试试看:

    1. 首先找到是否到达滚动视图底部。将onScrollChanged注册到Scroll视图

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

    我希望这对你有用。如果遇到任何问题,请告诉我。