2015-09-17 10 views
8

Ho una ListView in un ScrollView per mostrare i commenti e mi piacerebbe fare quanto segue:Passo al genitore Scrollview quando ListView sopra/sotto

Quando l'utente fa scorrere verso il basso, in primo luogo il ScrollView dovrebbe completamente scorrimento giù come l'elenco è in fondo. Una volta inattivo, lo Listiew dovrebbe iniziare a scorrere.

Analogamente, quando l'utente sta scorrendo verso l'alto, prima lo ListView (ordine invertito qui!) Dovrebbe scorrere verso l'alto, prima che lo ScrollView inizi a scorrere.

Finora ho fatto quanto segue:

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

I registri innescano al momento giusto, ma il ScrollView non si muove anche se torno falso.

Ho anche provato ad aggiungere v.getParent().requestDisallowInterceptTouchEvent(false); alle istruzioni, ma anche questo non ha funzionato.

Come posso farlo funzionare?

+0

Ho provato a fare questo (nidificazione un controllo ListView nel mio ScrollView) e non ho potuto farlo funzionare. Ho finito con l'utilizzo di due NestedScrollView – PeonProgrammer

+0

Ho esaminato anche la classe NestedScrollView, ma come indicato su altri thread le visualizzazioni di listino hanno alcune funzioni aggiuntive rispetto ad esempio a LinearLayout all'interno di una scrollview – Gooey

+0

Generalmente raccomanderei l'uso di una vista di intestazione in un ListView, invece di nidificare un ListView all'interno di una ScrollView - I contenitori scroll interconnessi pre-RecyclerView sono piuttosto dolorosi. –

risposta

8

È possibile creare un costume ScrollView e ListView e sovrascrivere

onInterceptTouchEvent(MotionEvent event) 

come questo:

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

In questo modo ogni Touch Down sul ListView mentre si è in fondo ScrollView andrà a il ListView.

Questa è solo un'implementazione abbozzo, ma penso che si potrebbe iniziare da questo facendo la stessa cosa per rilevare quando si è in cima alla ListView

Come nota vorrei provare un'implementazione più semplice utilizzando solo un ListView con il tuo attuale contenuto di ScrollView aggiunto come intestazione di ListView utilizzando listView.addHeaderView(scrollViewContent).Non so se questo si adatta alle tue esigenze.

EDIT:

rilevare quando dovrebbe iniziare lo scorrimento del ScrollView. Mantenere un riferimento a ListView nello ScrollView. Quando l'utente sta scorrendo verso l'alto e il ListView si trova in alto, l'evento può essere consumato dallo 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; 
} 

Il metodo listIsAtTop in ListView si presenta così:

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

Il problema con questo approccio è che esiste una dipendenza circolare tra listview e scrollview. Ho provato a implementare qualcosa con il metodo di intercettazione touch, ma poiché l'ordine è invertito quando si scorre, la scrollview deve "controllare" se la lista è fatta prima. – Gooey

+0

Controlla la mia modifica alla risposta. Ho fatto un test e funziona, ma non sono sicuro che questo sia quello che stai cercando di ottenere. Devi solo impostare un riferimento alla listview nella scrollview. Il codice potrebbe richiedere ulteriori ritocchi e pulizia. – GeorgeP

0

Try This:

  1. In primo luogo trovare se raggiunto a ScrollView Bottom. Registrare il onScrollChanged alla visualizzazione di scorrimento

    @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. Verificare se si raggiunge al Top di ListView. Controllare se 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!"); 
           } 
          } 
    
         } 
        }); 
    

Spero che questo funziona per voi. Se si verificano problemi, per favore fatemelo sapere.

+0

Rilevare se ho raggiunto la cima o il fondo è ciò che il mio codice già fa, voglio comunque passare eventi di movimento alla scrollview genitore a seconda di questo stato. – Gooey

4

Non dovresti inserire ListView all'interno di ScrollView, ma puoi raggiungere il tuo requisito utilizzando ExpandableHeightListView. Questo renderà piena altezza Listview all'interno di ScrollView. Non è necessario aggiungere 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> 

E un altro modo per raggiungere la vostra esigenza è RecyclerView con l'intestazione.

+0

Mentre funziona, non è proprio quello che ho chiesto. Questo mostra solo tutti gli elementi sotto il contenuto, potrebbe anche gettare le viste all'interno di un LinearLayout. – Gooey

Problemi correlati