2016-09-27 2 views
2

나는 CoordinatorLayout 두 아이들이, 헤더 역할을하는 ViewRecyclerView :사용자 정의 CoordinatorLayout.Behavior 및 RecyclerView 스크롤 문제

<android.support.design.widget.CoordinatorLayout 
    android:id="@+id/coordinator" 
    android:layout_width="match_parent" 
    android:layout_height="match_parent"> 

    <LinearLayout 
     android:id="@+id/view" 
     android:layout_width="match_parent" 
     android:layout_height="wrap_content" 
     android:orientation="vertical" 
     android:gravity="center_horizontal" 
     app:layout_behavior="some.package.AlphaBehavior"> 

     <ImageView 
      android:id="@+id/header_iv" 
      style="@style/some_style"/> 

     <TextView 
      android:id="@+id/header_retails_tv" 
      style="@style/some_style_tv" 
      android:text="@string/some_text"/> 

     </LinearLayout> 

     <android.support.v7.widget.RecyclerView 
      android:id="@+id/recyclerview" 
      android:layout_width="match_parent" 
      android:layout_height="match_parent" 
      android:clipToPadding="false" /> 

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

나는 헤더와 I의 크기에 RecyclerView에 동적으로 패딩을 설정 clipToPaddingfalse으로 설정하면 RecyclerView이 헤더 아래에 표시되고 사용자가 위로 스크롤하면 RecyclerView이 헤더보기 위에 표시됩니다.

내가 list까지 사용자가 스크롤 및 헤더가있을 때 페이드가 볼 수 있도록 할 때 다시보기에서 페이드를 달성하기 위해 사용자 정의 CoordinatorLayout.Behavior를 만들어의 AlphaBehavior :

public class AlphaBehavior extends CoordinatorLayout.Behavior { 

    private float alpha     = 1.0f; 
    private float scrolly    = 0.f; 
    private int headerSize = 0; 

    private Animation defaultFadeInAnimation; 

    public AlphaBehavior(Context context, AttributeSet attrs) { 
     super(context, attrs); 


     defaultFadeInAnimation = AnimationUtils.loadAnimation(context, android.R.anim.fade_in); 
    } 

    public void setHeaderSize(int headerSize) { 
     this.headerSize = headerSize; 
    } 

    @Override 
    public boolean layoutDependsOn(CoordinatorLayout parent, View child, View dependency) { 
     return dependency instanceof RecyclerView; 
    } 


    @Override 
    public void onNestedScroll(CoordinatorLayout coordinatorLayout, View child, View target, int dxConsumed, int dyConsumed, int dxUnconsumed, int dyUnconsumed) { 

     scrolly += dyConsumed; 

     Log.d(Constants.TAG, dyConsumed + "/" + dyUnconsumed + "/" + scrolly); 

     float totalScrollY = ((RecyclerView)target).computeVerticalScrollOffset(); 

     Log.d(Constants.TAG, "totalScrollY:" + totalScrollY); 

     alpha = (headerSize - totalScrollY)/headerSize; 

     if (alpha < 0.f) alpha = 0.f; 
     if (alpha > 1.0f) alpha = 1.f; 

     if (dyConsumed < 0 && totalScrollY > headerSize) { 
      alpha = 0.f; 
     } 

     Log.d(Constants.TAG, "alpha:" + alpha); 

     child.setAlpha(alpha); 
    } 

    @Override 
    public void onStopNestedScroll(CoordinatorLayout coordinatorLayout, View child, View target) { 

     int pos = ((LinearLayoutManager)((RecyclerView)target).getLayoutManager()).findFirstCompletelyVisibleItemPosition(); 

     Log.d(Constants.TAG, "pos:" + pos); 

     if (pos == 0 && child.getAlpha() == 0.f) { 
      child.startAnimation(defaultFadeInAnimation); 
     } 
    } 



    // overriding this in case we don't the other events are not called 
    @Override 
    public boolean onStartNestedScroll(CoordinatorLayout coordinatorLayout, View child, View directTargetChild, View target, int nestedScrollAxes) { 
     return nestedScrollAxes == ViewCompat.SCROLL_AXIS_VERTICAL; 
    } 
} 

그러나 나는 문제에 직면하고있다 : 사용자가 스크롤을 매우 빠르게하면 행동의 이벤트가 올바르게 호출되지 않는다. scrollY 회원은 전체 스크롤과 관련이 없으며 totalScrollY 회원 (RecyclerView 스크롤을 계산하여 얻음)이 올바르지 않습니다. onStopNestedScroll 이벤트에서 firstCompletelyVisibleItem을 찾으려고 시도했지만 recyclerView이 목록 시작 부분에 도달하면 2 또는 3 위치를 반환합니다.

+0

하여 확인하시기 바랍니다을 나는 어쩌면 누군가를 위해 유용 코드를 넣어 이안 레이크의 [대답] (https://medium.com/@ianhlake/flings-are-definitely-quite-a-bit-different-from- regular-scrolling-in-being-muchless-fine-grained-3dfc82062aaf). – wonsuc

답변

3

마지막으로 CoordinatorLayout.Behavior을 사용하는 대신 OnScrollListener을 사용하여 해결했으며 매력처럼 작동합니다.

사용자 정의 onScrollListener이보기 숨기기 :

public class HideViewOnScrollListener extends RecyclerView.OnScrollListener { 

    private float alpha = 1.f; 
    private float scrolly = 0.f; 

    private int heightViewToHide; 
    private final View viewToHide; 

    public HideViewOnScrollListener(View viewToHide) { 
     this.viewToHide = viewToHide; 

     heightViewToHide = viewToHide.getHeight(); 
     if (heightViewToHide == 0) { 

      ViewTreeObserver viewTreeObserver = viewToHide.getViewTreeObserver(); 
      viewTreeObserver.addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() { 
       @Override 
       public void onGlobalLayout() { 

        heightViewToHide = viewToHide.getHeight(); 

        if (heightViewToHide > 0) 
         viewToHide.getViewTreeObserver().removeOnGlobalLayoutListener(this); 
       } 
      }); 
     } 

    } 

    @Override 
    public void onScrolled(RecyclerView recyclerView, int dx, int dy) { 
     super.onScrolled(recyclerView, dx, dy); 

     scrolly += dy; 

     alpha = (heightViewToHide - scrolly)/heightViewToHide; 

     if (alpha < 0.f) alpha = 0.f; 
     if (alpha > 1.0f) alpha = 1.f; 

     if (dy < 0 && scrolly > heightViewToHide) { 
      alpha = 0.f; 
     } 

     viewToHide.setAlpha(alpha); 
    } 
} 

을 그리고 당신이 RecyclerView에 그런 식으로 추가 할 수 있습니다

recyclerView.addOnScrollListener(new HideViewOnScrollListener(viewToHide)); 
관련 문제