2015-11-08 4 views
12

Я реализовал разворачивающийся макет с помощью recyclerview, как показано в примере кода. Моя проблема в том, что, когда я бросаю список вниз, он не доходит до вершины.Развернуть appbarlayout, когда recycliewiew прокручивается/бросается наверх

Случается, что прокрутка останавливается прямо в точке, где предполагается завершить AppBarLayout.

Эффект, который я хочу на швыряя список вниз, список будет идти весь путь к вершине и выявить/расширить AppBarLayout

Мои minSdk: 14. Любая помощь или предложение с благодарностью.

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

Вы используете CoordinatorLayout? – Nedko

+0

Да, главный родитель - координатор – momoja

+0

Есть ли у вас какие-либо решения сейчас, momoja? – Wayne

ответ

8

Вы можете полностью развернуть или свернуть App Bar с помощью метода setExpanded(). Одна реализации может включать в себя переопределение dispatchTouchEvent() в вашем Activity классе, и автоматическое сворачивание/расширение вашего App Bar в зависимости от того, что свернут мимо точки на полпути:

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

В отношении автоматического скроллинга до последней позиции на броске , Я поместил некоторый код в GitHub, который показывает, как может быть programmatically smooth scroll to a specific location. Например, вызов прокрутки до list.size() - 1 на fling может привести к репликации поведения. Части этого кода по пути выполнены из StylingAndroid и Novoda блогов:

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

Редактировать:

AppBarManager в приведенном выше фрагменте кода относится к interface, используемой для связи с AppBarLayout в Activity , Свернуть/расширить методы панели приложений делают именно это, с анимацией. Последний метод используется для расчета количества RecyclerView строк видно на экране:

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

Привет, это не метод setexpanded, доступный только на api 23? – momoja

+0

@momoja Это часть библиотеки поддержки дизайна, поэтому нет. Вам может понадобиться v23 указанной библиотеки, что также может означать, что ваш 'targetSdkVersion' /' compileSdkVersion' должен быть 23, но вы можете использовать библиотеку на более низких API-устройствах. – PPartisan

+0

Что такое 'AppBarManager'? –

11

У меня была аналогичная проблема, и я использовал простой трюк, чтобы расширить AppBarLayout когда RecyclerView переместится наверх (вам необходимо иметь библиотеку поддержки> = 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

Определенно самое простое решение, и да, это работает. – Sakiboy

+0

Отличное решение. – Sermilion

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