2015-11-08 13 views
12

Ich implementierte ein collapsingtoolbar Layout mit einer Recyclerview wie in dem beigefügten Beispielcode gezeigt. Mein Problem ist, dass wenn ich die Liste nach unten schlebe, es nicht ganz nach oben geht.Erweitern Sie Appbarlayout, wenn Recyclerview nach oben scrollen/fling ist

Was passiert ist, dass das Scrollen genau an dem Punkt stoppt, an dem das AppBarLayout enden soll.

Der Effekt, den ich will, ist nach unten die Liste auf schleudert, wird die Liste den ganzen Weg nach oben und zeigen/erweitern Sie den AppBarLayout

Mein minSdk 14. Jede Hilfe oder Vorschlag ist, wird sehr geschätzt.

<?xml version="1.0" encoding="utf-8"?> 

<android.support.design.widget.AppBarLayout> 

    <android.support.design.widget.CollapsingToolbarLayout 
     app:layout_scrollFlags="scroll|exitUntilCollapsed"> 

     <LinearLayout 
      app:layout_collapseMode="parallax"> 

      //some elements 

     </LinearLayout> 

    </android.support.design.widget.CollapsingToolbarLayout> 

</android.support.design.widget.AppBarLayout> 

<android.support.v7.widget.RecyclerView 
    app:layout_behavior="@string/appbar_scrolling_view_behavior"/> //value android.support.design.widget.AppBarLayout$ScrollingViewBehavior 

<android.support.v7.widget.Toolbar 
    app:popupTheme="@style/AppTheme.PopupOverlay" 
    app:layout_collapseMode="parallax" /> 

+0

Verwenden Sie CoordinatorLayout? – Nedko

+0

Ja, der Hauptelternteil ist ein Koordinator – momoja

+0

Haben Sie irgendwelche Lösungen, momoja? – Wayne

Antwort

8

Sie können sich voll erweitern oder die App-Leiste mit dem setExpanded() Verfahren kollabieren. Eine Implementierung könnte beinhalten dispatchTouchEvent() in Ihrer Activity Klasse überschreiben, und auto-Kollabieren/Erweiterung Ihrer App Bar basierend darauf, ob es nach der Hälfte zusammengebrochen ist:

@Override 
public boolean dispatchTouchEvent(MotionEvent event) { 
    if (event.getAction() == MotionEvent.ACTION_UP) { 
     float per = Math.abs(mAppBarLayout.getY())/mAppBarLayout.getTotalScrollRange(); 
     boolean setExpanded = (per <= 0.5F); 
     mAppBarLayout.setExpanded(setExpanded, true); 
    } 
    return super.dispatchTouchEvent(event); 
} 

In Bezug auf automatisch auf einem fling auf die letzte Position Scrollen Ich habe Code auf GitHub geschrieben, der zeigt, wie man zu programmatically smooth scroll to a specific location hilft. Beispielsweise könnte das Aufrufen eines Bildlaufs zu list.size() - 1 auf einem fling das Verhalten replizieren. Teile dieses Codes durch die Art und Weise von den StylingAndroid und Novoda Blogs angepasst:

public class RecyclerLayoutManager extends LinearLayoutManager { 

    private AppBarManager mAppBarManager; 
    private int visibleHeightForRecyclerView; 

    public RecyclerLayoutManager(Context context) { 
     super(context); 
    } 

    @Override 
    public void smoothScrollToPosition(RecyclerView recyclerView, RecyclerView.State state, int position) { 
     View firstVisibleChild = recyclerView.getChildAt(0); 
     final int childHeight = firstVisibleChild.getHeight(); 
     int distanceInPixels = ((findFirstVisibleItemPosition() - position) * childHeight); 
     if (distanceInPixels == 0) { 
      distanceInPixels = (int) Math.abs(firstVisibleChild.getY()); 
     } 
     //Called Once 
     if (visibleHeightForRecyclerView == 0) { 
      visibleHeightForRecyclerView = mAppBarManager.getVisibleHeightForRecyclerViewInPx(); 
     } 
     //Subtract one as adapter position 0 based 
     final int visibleChildCount = visibleHeightForRecyclerView/childHeight - 1; 

     if (position <= visibleChildCount) { 
      //Scroll to the very top and expand the app bar 
      position = 0; 
      mAppBarManager.expandAppBar(); 
     } else { 
      mAppBarManager.collapseAppBar(); 
     } 

     SmoothScroller smoothScroller = new SmoothScroller(recyclerView.getContext(), Math.abs(distanceInPixels), 1000); 
     smoothScroller.setTargetPosition(position); 
     startSmoothScroll(smoothScroller); 
    } 

    public void setAppBarManager(AppBarManager appBarManager) { 
     mAppBarManager = appBarManager; 
    } 

    private class SmoothScroller extends LinearSmoothScroller { 
     private static final int TARGET_SEEK_SCROLL_DISTANCE_PX = 10000; 
     private final float distanceInPixels; 
     private final float duration; 

     public SmoothScroller(Context context, int distanceInPixels, int duration) { 
      super(context); 
      this.distanceInPixels = distanceInPixels; 
      float millisecondsPerPx = calculateSpeedPerPixel(context.getResources().getDisplayMetrics()); 
      this.duration = distanceInPixels < TARGET_SEEK_SCROLL_DISTANCE_PX ? 
        (int) (Math.abs(distanceInPixels) * millisecondsPerPx) : duration; 
     } 

     @Override 
     public PointF computeScrollVectorForPosition(int targetPosition) { 
      return RecyclerLayoutManager.this 
        .computeScrollVectorForPosition(targetPosition); 
     } 

     @Override 
     protected int calculateTimeForScrolling(int dx) { 
      float proportion = (float) dx/distanceInPixels; 
      return (int) (duration * proportion); 
     } 
    } 
} 

Edit:

AppBarManager im obigen Code-Schnipsel zu einem mit dem AppBarLayout in einem Activity zu kommunizieren interface verweist . Zusammenfassen/erweitern App-Leiste-Methoden tun genau das mit Animationen. Die letzte Methode wird verwendet, um die Anzahl der RecyclerView Zeilen auf dem Bildschirm sichtbar zu berechnen:

AppBarManager.java

public interface AppBarManager { 

    void collapseAppBar(); 
    void expandAppBar(); 
    int getVisibleHeightForRecyclerViewInPx(); 

} 

MainActivity.java

public class MainActivity extends AppCompatActivity implements AppBarManager{ 

@Override 
public void collapseAppBar() { 
    mAppBarLayout.setExpanded(false, true); 
} 

@Override 
public void expandAppBar() { 
    mAppBarLayout.setExpanded(true, true); 
} 

@Override 
public int getVisibleHeightForRecyclerViewInPx() { 

    if (mRecyclerFragment == null) mRecyclerFragment = 
      (RecyclerFragment) getSupportFragmentManager().findFragmentByTag(RecyclerFragment.TAG); 

    int windowHeight, appBarHeight, headerViewHeight; 
    windowHeight = getWindow().getDecorView().getHeight(); 
    appBarHeight = mAppBarLayout.getHeight(); 
    headerViewHeight = mRecyclerFragment.getHeaderView().getHeight(); 
    return windowHeight - (appBarHeight + headerViewHeight); 
} 
+1

Hallo, ist die Methode setexpanded nicht nur auf API 23 verfügbar? – momoja

+0

@momoja Es ist Teil der Design-Support-Bibliothek, also nein. Sie benötigen möglicherweise v23 dieser Bibliothek, was auch bedeuten kann, dass Ihre 'targetSdkVersion' /' compileSdkVersion'23 sein muss, aber Sie können die Bibliothek auf niedrigeren API-Geräten verwenden. – PPartisan

+0

Was ist 'AppBarManager' hier? –

11

Ich hatte ähnliches Problem und ich verwenden, um einen einfachen Trick AppBarLayout zu erweitern, wenn RecyclerView fling to top (Sie benötigen Unterstützung Bibliothek> = 23.xx)

mRecyclerView.addOnScrollListener(new RecyclerView.OnScrollListener() { 
      @Override 
      public void onScrollStateChanged(RecyclerView recyclerView, int newState) { 
       super.onScrollStateChanged(recyclerView, newState); 
       if (newState == RecyclerView.SCROLL_STATE_IDLE) { 
        int firstVisiblePosition = linearLayoutManager.findFirstCompletelyVisibleItemPosition(); 
        if (firstVisiblePosition == 0) { 
         mAppBarLayout.setExpanded(true, true); 
        } 
       } 
      } 
}); 
+0

Definitiv die einfachste Lösung, und ja, es funktioniert. – Sakiboy

+0

Tolle Lösung. – Sermilion

Verwandte Themen