2016-02-05 18 views
9

ho una funzionalità di elenco abbastanza tipico utilizzando un CoordinatorLayout, AppBarLayout, SwipeRefreshLayout e RecyclerView -arresto AppBarLayout scorre fuori dallo schermo quando NestedScrollView è vuoto

Quando il RecyclerView ha un contenuto sufficiente a scorrere, la pagina sembra che vada bene. Quando RecyclerView è vuoto o non ha abbastanza contenuto per scorrere, tuttavia, il comportamento è che i bambini di AppBarLayout con app:layout_scrollFlags="scroll|enterAlwaysCollapsed" continueranno a scorrere, il che sembra strano.

C'è un modo per interrompere lo scorrimento dei bambini di AppBarLayout quando NestedScrollView è vuoto?

enter image description here

<?xml version="1.0" encoding="utf-8"?> 
<FrameLayout 
    xmlns:android="http://schemas.android.com/apk/res/android" 
    xmlns:app="http://schemas.android.com/apk/res-auto" 
    android:layout_width="match_parent" 
    android:layout_height="match_parent"> 

    <android.support.design.widget.CoordinatorLayout 
     android:id="@+id/coordinatorLayout" 
     android:background="@android:color/transparent" 
     android:layout_width="match_parent" 
     android:layout_height="match_parent"> 

     <android.support.design.widget.AppBarLayout 
      android:layout_width="match_parent" 
      android:layout_height="wrap_content" 
      android:background="@android:color/transparent" 
      android:elevation="4dp"> 

      <LinearLayout 
       android:id="@+id/eventHeader" 
       android:layout_width="match_parent" 
       android:layout_height="wrap_content" 
       android:padding="16dp" 
       android:background="@color/green" 
       android:orientation="horizontal" 
       app:layout_scrollFlags="scroll|enterAlwaysCollapsed"> 

       <View 
        android:layout_width="0dp" 
        android:layout_height="0dp" 
        android:layout_weight="1"/> 

       <TextView 
        android:layout_width="wrap_content" 
        android:layout_height="wrap_content" 
        android:text="scroll|enterAlwaysCollapsed" 
        android:textColor="@color/white" 
        android:textSize="15sp"/> 

       <View 
        android:layout_width="0dp" 
        android:layout_height="0dp" 
        android:layout_weight="1"/> 

      </LinearLayout> 

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

     <android.support.v4.widget.SwipeRefreshLayout 
      android:id="@+id/swipeToRefresh" 
      android:layout_width="match_parent" 
      android:layout_gravity="fill_vertical" 
      android:layout_height="match_parent" 
      app:layout_behavior="@string/appbar_scrolling_view_behavior"> 

      <android.support.v7.widget.RecyclerView 
       android:id="@+id/recyclerView" 
       android:layout_width="match_parent" 
       android:layout_height="match_parent" 
       android:background="@android:color/transparent" 
       android:dividerHeight="0dp" 
       android:layout_gravity="fill_vertical" 
       android:drawSelectorOnTop="true" 
       android:listSelector="@drawable/selector_ripple_grey_transparent" 
       android:scrollbars="vertical"/> 

     </android.support.v4.widget.SwipeRefreshLayout> 

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

    <TextView 
     android:id="@+id/noData" 
     android:layout_width="wrap_content" 
     android:layout_height="wrap_content" 
     android:layout_gravity="center" 
     android:padding="16dp" 
     android:text="@string/no_data_available" 
     android:textSize="17sp"/> 

</FrameLayout> 

risposta

5

Non sono sicuro quanto elegante una soluzione questo non è che, mi escludeva l'evento onStartNestedScroll() a fuoco solo se il NestedScrollView è scorrevole (in questo caso un RecyclerView)

a onCreate ():

CoordinatorLayout.LayoutParams layoutParams = (CoordinatorLayout.LayoutParams) mAppBarLayout.getLayoutParams(); 
layoutParams.setBehavior(new AppBarLayoutNoEmptyScrollBehavior(mAppBarLayout, mRecyclerView)); 

Comportamento:

0.123.
public class AppBarLayoutNoEmptyScrollBehavior extends AppBarLayout.Behavior { 

    AppBarLayout mAppBarLayout; 
    RecyclerView mRecyclerView; 
    public AppBarLayoutNoEmptyScrollBehavior(AppBarLayout appBarLayout, RecyclerView recyclerView) { 
     mAppBarLayout = appBarLayout; 
     mRecyclerView = recyclerView; 
    } 

    public boolean isRecylerViewScrollable(RecyclerView recyclerView) { 
     int recyclerViewHeight = recyclerView.getHeight(); // Height includes RecyclerView plus AppBarLayout at same level 
     int appCompatHeight = mAppBarLayout != null ? mAppBarLayout.getHeight() : 0; 
     recyclerViewHeight -= appCompatHeight; 

     return recyclerView.computeVerticalScrollRange() > recyclerViewHeight; 
    } 

    @Override 
    public boolean onStartNestedScroll(CoordinatorLayout parent, AppBarLayout child, View directTargetChild, View target, int nestedScrollAxes) { 
     if (isRecylerViewScrollable(mRecyclerView)) { 
      return super.onStartNestedScroll(parent, child, directTargetChild, target, nestedScrollAxes); 
     } 
     return false; 
    } 

} 

EDIT

soluzione Modificato come RecyclerView dà altezza visibile altezza RecyclerView e altezza AppBarLayout (che è l'altezza CoordinatorLayout).

Tuttavia, se il gesto di scorrimento viene avviato nell'area AppBarLayout visibile, verrà eseguito uno scorrimento , anche se si aggiunge questo comportamento all'AppBarLayout. Questa risposta quindi non è una soluzione al problema.

2

(Basato su: Reference)

(1) Creare questa classe.

public class AppBarLayoutBehaviorForEmptyRecyclerView extends AppBarLayout.Behavior 
{ 
    private boolean canRecyclerViewBeScrolled = false; 

    public AppBarLayoutBehaviorForEmptyRecyclerView() 
    { 
    } 

    public AppBarLayoutBehaviorForEmptyRecyclerView(Context context, AttributeSet attrs) 
    { 
     super(context, attrs); 
    } 

    @Override 
    public boolean onInterceptTouchEvent(CoordinatorLayout parent, AppBarLayout child, MotionEvent ev) 
    { 
     return canRecyclerViewBeScrolled && super.onInterceptTouchEvent(parent, child, ev); 
    } 

    @Override 
    public boolean onStartNestedScroll(CoordinatorLayout parent, AppBarLayout child, View directTargetChild, View target, int nestedScrollAxes) 
    { 
     updateScrollable(target); 
     return canRecyclerViewBeScrolled && super.onStartNestedScroll(parent, child, directTargetChild, target, nestedScrollAxes); 
    } 

    @Override 
    public boolean onNestedFling(CoordinatorLayout coordinatorLayout, AppBarLayout child, View target, float velocityX, float velocityY, boolean consumed) 
    { 
     return canRecyclerViewBeScrolled && super.onNestedFling(coordinatorLayout, child, target, velocityX, velocityY, consumed); 
    } 

    private void updateScrollable(View targetChild) 
    { 
     if(targetChild instanceof RecyclerView) 
     { 
      RecyclerView.Adapter adapter = ((RecyclerView) targetChild).getAdapter(); 

      canRecyclerViewBeScrolled = adapter != null && adapter.getItemCount() > 0; 
     } 
     else 
     { 
      canRecyclerViewBeScrolled = true; 
     } 
    } 
} 

(2) Aggiungi al vostro elemento XML AppBarLayout il seguente attributo:

app:layout_behavior="com.xxxx.xxxxxx.AppBarLayoutBehaviorForEmptyRecyclerView" 
0

Dopo il caricamento dei dati al vostro RecyclerView, se è vuoto, solo disalbe la bandiera di scorrimento manuale:

AppBarLayout.LayoutParams toolbarLayoutParams = (AppBarLayout.LayoutParams) mEventHeader.getLayoutParams(); 
toolbarLayoutParams.setScrollFlags(0); 
mEventHeader.setLayoutParams(toolbarLayoutParams); 

E se non vuoto, imposta il flag di scorrimento:

AppBarLayout.LayoutParams toolbarLayoutParams = (AppBarLayout.LayoutParams) mEventHeader.getLayoutParams(); 
toolbarLayoutParams.setScrollFlags(AppBarLayout.LayoutParams.SCROLL_FLAG_SCROLL | AppBarLayout.LayoutParams.SCROLL_FLAG_ENTER_ALWAYS); 
mEventHeader.setLayoutParams(toolbarLayoutParams); 
0

Graeme risposta è ok ma anche aggiunto nel costruttore

public AppBarLayoutOnEmptyRecyclerViewScrollBehavior(@NonNull AppBarLayout appBarLayout, @NonNull RecyclerView recyclerView) { 
    this.appBarLayout = checkNotNull(appBarLayout); 
    this.recyclerView = checkNotNull(recyclerView); 

    setDragCallback(new DragCallback() { 
     @Override 
     public boolean canDrag(@NonNull AppBarLayout appBarLayout) { 
      return isRecylerViewScrollable(recyclerView); 
     } 
    }); 
} 

così quando RecyclerView è vuoto Ho anche disabilitare trascinate dal AppBarLayout

Problemi correlati