2015-09-17 4 views
8

Я имею в ScrollViewListView, чтобы показать комментарии, и я хотел бы сделать следующее:Pass событие движения к родительскому Scrollview когда Listview сверху/снизу

Когда пользователь пойло вниз, сначала 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; 
     } 
    }); 

Бревна вызвать в нужный момент, однако ScrollView не будет двигаться, даже если я вернусь ложным.

Я также попытался добавить v.getParent().requestDisallowInterceptTouchEvent(false); к утверждениям, но это тоже не сработало.

Как я могу заставить его работать?

+0

Я пытался сделать это (гнездящихся в ListView в моей Scrollview), и я не мог заставить его работать. Я закончил использование двух NestedScrollView – PeonProgrammer

+0

. Я также посмотрел на класс NestedScrollView, но, как указано в других разделах, в списках просмотров есть некоторые дополнительные функции, например LinearLayout внутри scrollview – Gooey

+0

Обычно я бы рекомендовал использовать представление заголовка в ListView, вместо этого вложенности ListView внутри ScrollView - вложенные контейнеры прокрутки pre-RecyclerView несколько болезненны. –

ответ

8

Вы можете создать собственный 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 в то время как вы находитесь в нижней части ScrollView пойдет ListView.

Это только эскиз реализации, но я думаю, что вы могли бы начать с этого, делая то же самое, чтобы обнаружить, когда вы находитесь на вершине ListView

Как примечанием я хотел бы попробовать более простой реализации с помощью просто ListView с текущим содержимым вас ScrollView добавлено в качестве заголовка ListView с помощью listView.addHeaderView(scrollViewContent).Я не знаю, соответствует ли это вашим потребностям.

EDIT:

Детектирование когда следует начать прокрутку ScrollView. Сохранение ссылки 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; 
} 

Метод listIsAtTop в ListView выглядит следующим образом:

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

Проблема с этим подходом заключается в том, что существует циклическая зависимость между списком и прокруткой. Я попытался реализовать что-то с помощью метода сенсорного перехвата, но по мере того, как при обращении вспять порядок отменяется, scrollview должен «проверять», если сначала выполняется просмотр списка. – Gooey

+0

Отметьте мое изменение для ответа. Я сделал тест, и он работает, но я не уверен, что это то, чего вы пытаетесь достичь. Вам просто нужно установить ссылку на список в прокрутке. Код может потребовать дополнительной настройки и очистки. – GeorgeP

0

Попробуйте:

  1. Сначала найдите, если вы достигли в Scrollview Bottom. Зарегистрируйте 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!"); 
           } 
          } 
    
         } 
        }); 
    

Я надеюсь, что это работает для вас. Если у вас возникнут какие-либо проблемы, сообщите мне.

+0

Обнаружение, если я достиг верхнего или нижнего - это то, что мой код уже делает, однако я хочу передать события движения родительскому прокрутку в зависимости от этого состояния. – Gooey

4

Вы не должны помещать ListView внутри ScrollView, но вы можете достичь своего требования, используя ExpandableHeightListView. Это сделает полный список Listview внутри ScrollView. Не нужно добавлять 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 с заголовком.

+0

Хотя он действительно работает, на самом деле я этого не спрашивал. Это просто отображает все элементы, находящиеся под содержимым, может также отображать представления внутри LinearLayout. – Gooey

 Смежные вопросы

  • Нет связанных вопросов^_^