2015-09-17 5 views
8

Ich habe ein ListView in einem ScrollView Kommentare zu zeigen, und ich möchte folgendes tun:Pass Bewegung Ereignis Mutterscroll wenn Listview oben/unten

Wenn der Benutzer klaut, indem Sie zuerst die ScrollView sollte vollständig blättern unten, da die Liste unten ist. Sobald es ganz unten ist, sollte die Listiew mit dem Scrollen beginnen.

In ähnlicher Weise, wenn der Benutzer scrollt, zuerst die ListView (Bestellung hier umgekehrt!) Nach oben scrollen, bevor die ScrollView beginnt Scrollen.

Bisher habe ich folgendes getan:

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

Die Protokolle im richtigen Moment auslösen, aber die ScrollView nicht einmal bewegen, obwohl ich falsch zurück.

Ich habe auch versucht, v.getParent().requestDisallowInterceptTouchEvent(false); zu den Aussagen hinzuzufügen, aber das hat auch nicht funktioniert.

Wie kann ich es funktionieren lassen?

+0

Ich habe versucht, dies zu tun (ein Listview in meinem Scroll nisten) und ich konnte es nicht zur Arbeit kommen. Ich habe am Ende zwei NestedScrollView – PeonProgrammer

+0

Ich schaute auch auf die NestedScrollView-Klasse, aber wie auf andere Threads hingewiesen listviews haben einige zusätzliche Funktionen über zum Beispiel eine LinearLayout innerhalb einer scrollview – Gooey

+0

Generell würde ich empfehlen, stattdessen eine Header-Ansicht in einer ListView Verschachteln einer ListView in einer ScrollView - verschachtelte Scroll-Container Pre-RecyclerView ist etwas schmerzhaft. –

Antwort

8

können Sie eine benutzerdefinierte erstellen ScrollView und ListView und

onInterceptTouchEvent(MotionEvent event) 

wie dies außer Kraft setzen:

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

diese Weise wird jede unten Tippen Sie auf der ListView, während Sie am unteren Rand des ScrollView sind gehen an die ListView.

Dies ist nur eine Skizze der Umsetzung, aber ich glaube, Sie von diesem beginnen könnten das Gleiche, indem Sie zu erkennen, wenn Sie an der Spitze der eine einfachere Implementierung durch die Verwendung Ich würde ListView

Als Hinweis sind versuchen nur ein ListView mit dem aktuellen Inhalt von Ihnen ScrollView hinzugefügt als Header von ListView mit listView.addHeaderView(scrollViewContent).Ich weiß nicht, ob das Ihren Bedürfnissen entspricht.

EDIT:

Erkennen, wann beginnen sollte die ScrollView scrollen. Eine Referenz von ListView in der ScrollView halten. Wenn der Benutzer nach oben scrollt und die ListView oben ist, lassen Sie das Ereignis von ScrollView konsumiert werden.

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

Verfahren listIsAtTop in Listview sieht wie folgt aus:

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

Das Problem bei diesem Ansatz besteht darin, dass zwischen der Listenansicht und der Bildlaufansicht eine zyklische Abhängigkeit besteht. Ich habe versucht, etwas mit der Touch-Intercept-Methode zu implementieren, aber da die Reihenfolge beim Scrollen umgekehrt ist, muss der Scrollview "überprüfen", ob die Listview zuerst ausgeführt wird. – Gooey

+0

Überprüfen Sie meine Bearbeitung zu der Antwort. Ich habe einen Test gemacht und es funktioniert, aber ich bin mir nicht sicher, dass es das ist, was Sie erreichen wollen. Sie müssen nur einen Verweis auf die Listview in der Scrollview setzen. Der Code erfordert möglicherweise einige zusätzliche Feinabstimmungen und Bereinigung. – GeorgeP

0

Try This:

  1. Zuerst finden, wenn Sie bei Scroll Bottom erreicht. Registrieren Sie den onScrollChanged auf Ihre Scroll Ansicht

    @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. Überprüfen Sie, ob Sie an der Spitze von Listview erreichen. Überprüfen Sie, ob 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!"); 
           } 
          } 
    
         } 
        }); 
    

Ich hoffe, das für Sie arbeitet. Wenn Sie Probleme haben, lassen Sie es mich bitte wissen.

+0

Wenn ich feststelle, ob ich den oberen oder unteren Rand erreicht habe, möchte ich, je nach diesem Zustand, Bewegungsereignisse an den übergeordneten scrollview übergeben. – Gooey

4

Sie sollten ListView nicht in ScrollView einfügen, aber Sie können Ihre Anforderung mit ExpandableHeightListView erreichen. Dies macht ListView in voller Höhe innerhalb von ScrollView. Sie müssen keinen TouchListener hinzufügen.

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

Und ein anderer Weg, um Ihre Anforderung zu erreichen, ist RecyclerView mit Kopf.

+0

Während es funktioniert, ist es nicht wirklich, was ich gefragt habe. Dies zeigt nur alle Elemente unter dem Inhalt, könnte dann Ansichten in ein LinearLayout dann werfen. – Gooey

Verwandte Themen