Pārlūkot izejas kodu

[메인][New] 가로 스냅퍼 추가, 마지막 뷰 세부 설정

hyodong.min 7 gadi atpakaļ
vecāks
revīzija
31f5508d17

+ 71 - 14
app/src/main/java/kr/co/zumo/app/lifeplus/view/screen/main/MainCategorySnapper.java

@@ -3,6 +3,7 @@ package kr.co.zumo.app.lifeplus.view.screen.main;
 import android.graphics.PointF;
 import android.support.annotation.NonNull;
 import android.support.annotation.Nullable;
+import android.support.v7.widget.LinearLayoutManager;
 import android.support.v7.widget.LinearSmoothScroller;
 import android.support.v7.widget.OrientationHelper;
 import android.support.v7.widget.RecyclerView;
@@ -11,6 +12,7 @@ import android.support.v7.widget.RecyclerView.SmoothScroller;
 import android.support.v7.widget.RecyclerView.SmoothScroller.ScrollVectorProvider;
 import android.support.v7.widget.SnapHelper;
 import android.util.DisplayMetrics;
+import android.util.Log;
 import android.view.View;
 import android.view.animation.DecelerateInterpolator;
 import android.widget.Scroller;
@@ -222,12 +224,20 @@ public class MainCategorySnapper extends RecyclerView.OnFlingListener {
       return;
     }
 
+//    int[] snapDistance = calculateDistanceToFinalSnap(layoutManager, snapView);
+//    snapDistance[0] -= snapOffset;  // 마지막 뷰일 경우 snapOffset 을 적용하면 부자연스럽게 스크롤 됨
+//    snapDistance[1] -= snapOffset;
+//    if (snapDistance[0] != 0 || snapDistance[1] != 0) {
+//      mRecyclerView.smoothScrollBy(snapDistance[0], snapDistance[1], new DecelerateInterpolator());
+//    }
+
     /**
      * 현재 스크롤 포지션에 가장 가까운 뷰로 스크롤 시킨다.
      * - recyclerView 의 스크롤을 이용하지않고 직접 스크롤시킨다.
      * - recyclerView 는 너무 빠름.
      */
     int position = layoutManager.getPosition(snapView);
+    Log.i("APP# MainCategorySnapper | snapToTargetExistingView", "|" + "position: " + position);
 
     SmoothScroller smoothScroller = createScroller(layoutManager);
     if (smoothScroller == null) {
@@ -271,9 +281,46 @@ public class MainCategorySnapper extends RecyclerView.OnFlingListener {
           // The associated RecyclerView has been removed so there is no action to take.
           return;
         }
+        int offset = snapOffset;
+        if (mRecyclerView.getChildAdapterPosition(targetView) == (mRecyclerView.getAdapter().getItemCount() - 1)) {
+          /**
+           * 보통 뷰일 때 스크롤 타겟 위치
+           * - 0 + offset
+           *
+           * 마지막 뷰일 때
+           * => offset = screenWidth - 마지막 뷰 사이즈
+           */
+          OrientationHelper helper = getOrientationHelper(layoutManager);
+          if (null != helper) {
+            offset = (layoutManager.getWidth() - helper.getDecoratedMeasurement(targetView));
+          }
+//          Log.e("APP#  MainCategorySnapper | onTargetFound", "|" + "layoutManager.getWidth(): " + layoutManager.getWidth());
+//          Log.e("APP#  MainCategorySnapper | onTargetFound", "|" + "helper.getDecoratedMeasurement(targetView): " + helper.getDecoratedMeasurement(targetView));
+//          Log.e("APP#  MainCategorySnapper | onTargetFound", "|" + "offset: " + offset);
+        }
         int[] snapDistances = calculateDistanceToFinalSnap(mRecyclerView.getLayoutManager(), targetView);
-        final int dx = snapDistances[0] - snapOffset;
-        final int dy = snapDistances[1] - snapOffset;
+        final int dx;
+        final int dy;
+
+        /**
+         * 방향을 고려해서 offset 적용한다. 항상 적용하면 긴쪽을 기준으로 time 이 계산되어서 이동 거리가 0일 경우 느리게 움직일 수 있다.
+         */
+        LinearLayoutManager linearLayoutManager = (LinearLayoutManager) layoutManager;
+        if (null != linearLayoutManager) {
+          if (linearLayoutManager.getOrientation() == LinearLayoutManager.HORIZONTAL) {
+            dx = snapDistances[0] - offset;
+            dy = snapDistances[1];
+          }
+          else {
+            dx = snapDistances[0];
+            dy = snapDistances[1] - offset;
+          }
+        }
+        else {
+          dx = snapDistances[0];
+          dy = snapDistances[1];
+        }
+
         final int time = calculateTimeForDeceleration(Math.max(Math.abs(dx), Math.abs(dy)));
         if (time > 0) {
           int newTime = Math.min(TIME_MAX, Math.max(time, TIME_MIN));
@@ -288,6 +335,16 @@ public class MainCategorySnapper extends RecyclerView.OnFlingListener {
     };
   }
 
+  private OrientationHelper getOrientationHelper(LayoutManager layoutManager) {
+    if (layoutManager.canScrollVertically()) {
+      return getVerticalHelper(layoutManager);
+    }
+    else if (layoutManager.canScrollHorizontally()) {
+      return getHorizontalHelper(layoutManager);
+    }
+    return null;
+  }
+
   /**
    * Override this method to snap to a particular point within the target view or the container
    * view on any axis.
@@ -338,11 +395,9 @@ public class MainCategorySnapper extends RecyclerView.OnFlingListener {
   @SuppressWarnings("WeakerAccess")
   @Nullable
   public View findSnapView(LayoutManager layoutManager) {
-    if (layoutManager.canScrollVertically()) {
-      return findTopView(layoutManager, getVerticalHelper(layoutManager));
-    }
-    else if (layoutManager.canScrollHorizontally()) {
-      return findTopView(layoutManager, getHorizontalHelper(layoutManager));
+    OrientationHelper helper = getOrientationHelper(layoutManager);
+    if (null != helper) {
+      return findTopView(layoutManager, helper);
     }
     return null;
   }
@@ -372,13 +427,14 @@ public class MainCategorySnapper extends RecyclerView.OnFlingListener {
     }
     int absClosest = Integer.MAX_VALUE;
 
-    int childMaxSize = 0;
+    int secondItemPositionMax = 0;
 
     for (int i = 0; i < childCount; ++i) {
       final View child = layoutManager.getChildAt(i);
       int childStart = helper.getDecoratedStart(child);
       int childEnd = helper.getDecoratedEnd(child);
-      int childSize = Math.abs(childEnd - childStart) + snapOffset;
+      int childSize = Math.abs(childEnd - childStart);
+      int secondItemPosition = childSize + snapOffset;
       int childCenter = childStart + (helper.getDecoratedMeasurement(child) >> 2);
       int absDistance = Math.abs(childCenter - (top + (childSize >> 2)));
 
@@ -388,21 +444,22 @@ public class MainCategorySnapper extends RecyclerView.OnFlingListener {
         closestChild = child;
       }
 
-      if (childMaxSize < childSize) {
-        childMaxSize = childSize;
+      if (secondItemPositionMax < secondItemPosition) {
+        secondItemPositionMax = secondItemPosition;
       }
 
       /**
        * 마지막이 기준 위치보다 왼쪽에 있으면 녀석을 타겟으로 본다.
        * - 마지막 녀석은 크기가 작아서 그걸로 확인
        */
-      if (childMaxSize > childSize) {
+      if (secondItemPositionMax > childSize) {
         // padding start + childSize > lastChild.x
 //        Log.w("APP# MainCategorySnapper | findTopView", "|" + "padding: " + helper.getStartAfterPadding());
-//        Log.w("APP# MainCategorySnapper | findTopView", "|" + "childMaxSize: " + childMaxSize);
+//        Log.w("APP# MainCategorySnapper | findTopView", "|" + "secondItemPositionMax: " + secondItemPositionMax);
+//        Log.w("APP# MainCategorySnapper | findTopView", "|" + "secondItemPosition: " + secondItemPosition);
 //        Log.w("APP# MainCategorySnapper | findTopView", "|" + "snapOffset: " + snapOffset);
 //        Log.w("APP# MainCategorySnapper | findTopView", "|" + "child.x: " + child.getX());
-        if (childMaxSize > child.getX()) {
+        if (secondItemPositionMax - (childSize >> 1) > child.getX()) {
           closestChild = child;
         }
       }