2015-09-17 7 views
8

mam ListView w ScrollView, aby wyświetlić komentarze i chciałbym aby wykonać następujące czynności:Przełęcz wydarzenie ruch do macierzystej Scrollview kiedy ListView w górnej/dolnej

Gdy użytkownik przejeżdża w dół, najpierw ScrollView powinien całkowicie przewijania w dół, ponieważ lista znajduje się na dole. Po całkowitym wyłączeniu, urządzenie Listiew powinno rozpocząć przewijanie.

Podobnie, gdy użytkownik przewija w górę, najpierw ListView (kolejność tutaj odwrócona!) Powinien przewinąć w górę, zanim rozpocznie się przewijanie ScrollView.

tej pory zrobiłem, co następuje:

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

Dzienniki wyzwolić w odpowiednim momencie, jednak ScrollView nie ruszy chociaż return false.

Próbowałem również dodać v.getParent().requestDisallowInterceptTouchEvent(false); do instrukcji, ale to też nie działało.

Jak mogę to sprawić?

+0

Próbowałem to zrobić (zagnieżdżanie listview w moim Scrollview) i nie mogę zmusić go do pracy. Skończyło się na użyciu dwóch NestedScrollView – PeonProgrammer

+0

Spojrzałem również na klasę NestedScrollView, ale jak wskazano w innych wątkach, odsyłacze mają pewne dodatkowe funkcje, na przykład LinearLayout wewnątrz przewijania – Gooey

+0

Ogólnie polecam używanie widoku nagłówka w ListView, zamiast tego zagnieżdżania ListView wewnątrz ScrollView - Zagnieżdżone kontenery przewijania pre-RecyclerView są dość bolesne. –

Odpowiedz

8

Można tworzyć niestandardowe ScrollView i ListView i zastąpić

onInterceptTouchEvent(MotionEvent event) 

takiego:

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

ten sposób każdy dół dotykowy na ListView gdy jesteś na dnie ScrollView trafi do ListView.

To tylko szkic realizacja ale myślę, że można zacząć od tego, wykonując to samo wykryć, kiedy jesteś na górze ListView

Na marginesie chciałbym spróbować łatwiejszą implementację za pomocą tylko ListView z aktualną treścią ciebie ScrollView dodaną jako nagłówek ListView za pomocą listView.addHeaderView(scrollViewContent).Nie wiem, czy to pasuje do twoich potrzeb.

EDIT:

Wykrywanie kiedy należy rozpocząć przewijanie ScrollView. Zachowanie odniesienia ListView w ScrollView. Gdy użytkownik przewija w górę, a ListView jest na górze, niech wydarzenie zostanie zużyte przez 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; 
} 

Sposób listIsAtTop w ListView wygląda następująco:

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

Problem z tym podejściem polega na tym, że istnieje zależność cykliczna między widokiem listy a widokiem przewijania. Próbowałem zaimplementować coś za pomocą metody przechwytywania dotykowego, ale ponieważ kolejność jest odwrócona podczas przewijania w górę, widok przewijania musi "sprawdzić", jeśli lista jest wykonywana jako pierwsza. – Gooey

+0

Sprawdź moją zmianę w odpowiedzi. Zrobiłem test i działa, ale nie jestem pewien, czy to właśnie próbujesz osiągnąć. Musisz tylko ustawić odniesienie do listy w widoku przewijania. Kod może wymagać dodatkowych ulepszeń i czyszczenia. – GeorgeP

0

Spróbuj to:

  1. Pierwszy znaleźć jeśli osiągnięte w Scrollview Bottom. Zarejestrować onScrollChanged do widoku przewijania

    @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. sprawdzić, czy można dotrzeć na szczycie ListView. Sprawdź, czy firstVisibleItem jest 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!"); 
           } 
          } 
    
         } 
        }); 
    

Mam nadzieję, że to działa dla Ciebie. Jeśli napotkasz jakiekolwiek problemy, daj mi znać.

+0

Wykrywanie, czy osiągnąłem górny lub dolny poziom, jest tym, co już robi mój kod, ale chcę przekazywać zdarzenia ruchu do nadrzędnego przewijania w zależności od tego stanu. – Gooey

4

Nie powinieneś umieszczać ListView wewnątrz ScrollView, ale możesz spełnić swoje wymagania, używając ExpandableHeightListView. Spowoduje to utworzenie pełnej listy Listview wewnątrz ScrollView. Nie trzeba dodawać 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> 

Innym sposobem na spełnienie tego wymogu jest RecyclerView z nagłówkiem.

+0

Podczas gdy to działa, nie jest to tak naprawdę, o co prosiłem. Po prostu pokazuje wszystkie elementy poniżej zawartości, a następnie może rzucać widokami wewnątrz LinearLayout. – Gooey

Powiązane problemy