Преглед изворни кода

[메인][New] 가로 스크롤 스냅퍼 수정

hyodong.min пре 7 година
родитељ
комит
7a900f4dfe

+ 52 - 142
app/src/main/java/kr/co/zumo/app/lifeplus/view/screen/main/MainCategorySnapper.java

@@ -3,7 +3,6 @@ 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;
@@ -14,7 +13,6 @@ import android.support.v7.widget.SnapHelper;
 import android.util.DisplayMetrics;
 import android.util.Log;
 import android.view.View;
-import android.view.ViewConfiguration;
 import android.view.animation.DecelerateInterpolator;
 import android.widget.Scroller;
 
@@ -37,6 +35,8 @@ public class MainCategorySnapper extends RecyclerView.OnFlingListener {
   private static final int TIME_MIN = 250;
 
   static final float MILLISECONDS_PER_INCH = 100f;
+  private static final float SCROLL_FRICTION = 5f; //1.5f  // 마찰계수를 늘려 준다. 최대 이동 거리가 줄어듬.
+
 
   RecyclerView mRecyclerView;
   private Scroller mGravityScroller;
@@ -66,7 +66,7 @@ public class MainCategorySnapper extends RecyclerView.OnFlingListener {
       @Override
       public void onScrolled(RecyclerView recyclerView, int dx, int dy) {
 //        Log.i("APP# MainCategorySnapper | onScrolledVertical", "|" + "dx: " + dx);
-        if (dx != 0 || dy != 0) {
+        if (dx != 0) {
           mScrolled = true;
         }
       }
@@ -96,8 +96,7 @@ public class MainCategorySnapper extends RecyclerView.OnFlingListener {
       return false;
     }
     int minFlingVelocity = 0; //mRecyclerView.getMinFlingVelocity();
-    return (Math.abs(velocityY) > minFlingVelocity || Math.abs(velocityX) > minFlingVelocity)
-      && snapFromFling(layoutManager, velocityX, velocityY);
+    return Math.abs(velocityX) > minFlingVelocity && snapFromFling(layoutManager, velocityX, velocityY);
   }
 
   /**
@@ -121,8 +120,8 @@ public class MainCategorySnapper extends RecyclerView.OnFlingListener {
     mRecyclerView = recyclerView;
     if (mRecyclerView != null) {
       setupCallbacks();
-      mGravityScroller = new Scroller(mRecyclerView.getContext(), new DecelerateInterpolator(10f));
-      mGravityScroller.setFriction(ViewConfiguration.getScrollFriction() * 10);    // 마찰계수를 늘려 줌
+      mGravityScroller = new Scroller(mRecyclerView.getContext(), new DecelerateInterpolator());
+      mGravityScroller.setFriction(SCROLL_FRICTION);
       snapToTargetExistingView();
     }
   }
@@ -156,10 +155,9 @@ public class MainCategorySnapper extends RecyclerView.OnFlingListener {
    */
   public int[] calculateScrollDistance(int velocityX, int velocityY) {
     int[] outDist = new int[2];
-    mGravityScroller.fling(0, 0, velocityX, velocityY,
-      Integer.MIN_VALUE, Integer.MAX_VALUE, Integer.MIN_VALUE, Integer.MAX_VALUE);
+    mGravityScroller.fling(0, 0, velocityX, velocityY, Integer.MIN_VALUE, Integer.MAX_VALUE, Integer.MIN_VALUE, Integer.MAX_VALUE);
     outDist[0] = mGravityScroller.getFinalX();
-    outDist[1] = mGravityScroller.getFinalY();
+    outDist[1] = 0; //mGravityScroller.getFinalY();
     return outDist;
   }
 
@@ -172,8 +170,7 @@ public class MainCategorySnapper extends RecyclerView.OnFlingListener {
    * @param velocityY     Fling velocity on the vertical axis.
    * @return true if it is handled, false otherwise.
    */
-  private boolean snapFromFling(@NonNull LayoutManager layoutManager, int velocityX,
-                                int velocityY) {
+  private boolean snapFromFling(@NonNull LayoutManager layoutManager, int velocityX, int velocityY) {
     if (!(layoutManager instanceof ScrollVectorProvider)) {
       return false;
     }
@@ -277,23 +274,7 @@ 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 = (helper.getEnd() - 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;
         final int dy;
@@ -301,21 +282,8 @@ public class MainCategorySnapper extends RecyclerView.OnFlingListener {
         /**
          * 방향을 고려해서 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];
-        }
+        dx = snapDistances[0];
+        dy = snapDistances[1]; // - offset;
 
         final int time = calculateTimeForDeceleration(Math.max(Math.abs(dx), Math.abs(dy)));
         if (time > 0) {
@@ -328,17 +296,12 @@ public class MainCategorySnapper extends RecyclerView.OnFlingListener {
       protected float calculateSpeedPerPixel(DisplayMetrics displayMetrics) {
         return MILLISECONDS_PER_INCH / displayMetrics.densityDpi;
       }
+
     };
   }
 
   private OrientationHelper getOrientationHelper(LayoutManager layoutManager) {
-    if (layoutManager.canScrollVertically()) {
-      return getVerticalHelper(layoutManager);
-    }
-    else if (layoutManager.canScrollHorizontally()) {
-      return getHorizontalHelper(layoutManager);
-    }
-    return null;
+    return getHorizontalHelper(layoutManager);
   }
 
   /**
@@ -358,20 +321,23 @@ public class MainCategorySnapper extends RecyclerView.OnFlingListener {
   @Nullable
   public int[] calculateDistanceToFinalSnap(@NonNull LayoutManager layoutManager, @NonNull View targetView) {
     int[] out = new int[2];
-    if (layoutManager.canScrollHorizontally()) {
-      out[0] = distanceToTop(layoutManager, targetView, getHorizontalHelper(layoutManager));
-    }
-    else {
-      out[0] = 0;
-    }
+    out[0] = distanceToCenter(layoutManager, targetView, getHorizontalHelper(layoutManager));
+    out[1] = 0;
 
-    if (layoutManager.canScrollVertically()) {
-      out[1] = distanceToTop(layoutManager, targetView, getVerticalHelper(layoutManager));
+    return out;
+  }
+
+  private int distanceToCenter(@NonNull RecyclerView.LayoutManager layoutManager, @NonNull View targetView, OrientationHelper helper) {
+    final int childStart = helper.getDecoratedStart(targetView);
+    final int containerStart;
+    if (layoutManager.getClipToPadding()) {
+      containerStart = helper.getStartAfterPadding() + snapOffset;
     }
     else {
-      out[1] = 0;
+      containerStart = snapOffset;
     }
-    return out;
+
+    return childStart - containerStart;
   }
 
   /**
@@ -393,82 +359,53 @@ public class MainCategorySnapper extends RecyclerView.OnFlingListener {
   public View findSnapView(LayoutManager layoutManager) {
     OrientationHelper helper = getOrientationHelper(layoutManager);
     if (null != helper) {
-      return findTopView(layoutManager, helper);
+      return findCenterView(layoutManager, helper);
     }
     return null;
   }
 
+
   /**
-   * Return the child view that is currently closest to the top of this parent.
+   * Return the child view that is currently closest to the center of this parent.
    *
-   * @param layoutManager The {@link LayoutManager} associated with the attached
+   * @param layoutManager The {@link RecyclerView.LayoutManager} associated with the attached
    *                      {@link RecyclerView}.
    * @param helper        The relevant {@link OrientationHelper} for the attached {@link RecyclerView}.
-   * @return the child view that is currently closest to the top of this parent.
+   * @return the child view that is currently closest to the center of this parent.
    */
   @Nullable
-  private View findTopView(LayoutManager layoutManager, OrientationHelper helper) {
+  private View findCenterView(RecyclerView.LayoutManager layoutManager,
+                              OrientationHelper helper) {
     int childCount = layoutManager.getChildCount();
     if (childCount == 0) {
       return null;
     }
 
     View closestChild = null;
-    final int top;
+    final int center;
     if (layoutManager.getClipToPadding()) {
-      top = helper.getStartAfterPadding();
+      center = helper.getStartAfterPadding() + helper.getTotalSpace() / 2;
     }
     else {
-      top = 0;
+      center = helper.getEnd() / 2;
     }
     int absClosest = Integer.MAX_VALUE;
-    int lastIndex = mRecyclerView.getAdapter().getItemCount() - 1;
 
-    int secondItemPositionMax = 0;
-
-    for (int i = 0; i < childCount; ++i) {
+    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);
-      int secondItemPosition = childSize + snapOffset;
-      int childCenter = childStart + (helper.getDecoratedMeasurement(child) >> 2);
-      int absDistance = Math.abs(childCenter - (top + (childSize >> 2)));
-
-      /** if child top is closer than previous closest, set it as closest  **/
+      int childCenter = helper.getDecoratedStart(child)
+        + (helper.getDecoratedMeasurement(child) / 2);
+      int absDistance = Math.abs(childCenter - center);
+
+      /** if child center is closer than previous closest, set it as closest  **/
       if (absDistance < absClosest) {
         absClosest = absDistance;
         closestChild = child;
       }
-
-      if (secondItemPositionMax < secondItemPosition) {
-        secondItemPositionMax = secondItemPosition;
-      }
-
-      /**
-       * 마지막이 기준 위치보다 왼쪽에 있으면 녀석을 타겟으로 본다.
-       */
-      if (mRecyclerView.getChildAdapterPosition(child) == lastIndex) {
-//        Log.w("APP# MainCategorySnapper | findTopView", "|" + "padding: " + helper.getStartAfterPadding());
-//        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 (secondItemPositionMax /*- (childSize >> 1)*/ > child.getX()) {
-          closestChild = child;
-        }
-      }
     }
     return closestChild;
   }
 
-  private int distanceToTop(@NonNull LayoutManager layoutManager, @NonNull View targetView, OrientationHelper helper) {
-    /**
-     * targetView 의 시작 위치(Top)를 반환한다.
-     */
-    return helper.getDecoratedStart(targetView);
-  }
-
   /**
    * Estimates a position to which SnapHelper will try to scroll to in response to a fling.
    *
@@ -492,7 +429,7 @@ public class MainCategorySnapper extends RecyclerView.OnFlingListener {
 
     int min = 0;
     // 속도가 minVelocity 보다 크면 기본 1칸 이동
-    if (Math.abs(velocityX) > minVelocity || Math.abs(velocityY) > minVelocity) {
+    if (Math.abs(velocityX) > minVelocity) {
       min = 1;
     }
     int result = Math.round(distance / distancePerChild);
@@ -543,29 +480,13 @@ public class MainCategorySnapper extends RecyclerView.OnFlingListener {
       return RecyclerView.NO_POSITION;
     }
 
-    int vDeltaJump, hDeltaJump;
-    if (layoutManager.canScrollHorizontally()) {
-      hDeltaJump = estimateNextPositionDiffForFling(layoutManager,
-        getHorizontalHelper(layoutManager), velocityX, 0);
-      if (vectorForEnd.x < 0) {
-        hDeltaJump = -hDeltaJump;
-      }
-    }
-    else {
-      hDeltaJump = 0;
-    }
-    if (layoutManager.canScrollVertically()) {
-      vDeltaJump = estimateNextPositionDiffForFling(layoutManager,
-        getVerticalHelper(layoutManager), 0, velocityY);
-      if (vectorForEnd.y < 0) {
-        vDeltaJump = -vDeltaJump;
-      }
-    }
-    else {
-      vDeltaJump = 0;
+    int hDeltaJump;
+    hDeltaJump = estimateNextPositionDiffForFling(layoutManager, getHorizontalHelper(layoutManager), velocityX, 0);
+    if (vectorForEnd.x < 0) {
+      hDeltaJump = -hDeltaJump;
     }
 
-    int deltaJump = layoutManager.canScrollVertically() ? vDeltaJump : hDeltaJump;
+    int deltaJump = hDeltaJump;
     if (deltaJump == 0) {
       return RecyclerView.NO_POSITION;
     }
@@ -620,10 +541,8 @@ public class MainCategorySnapper extends RecyclerView.OnFlingListener {
     if (minPosView == null || maxPosView == null) {
       return INVALID_DISTANCE;
     }
-    int start = Math.min(helper.getDecoratedStart(minPosView),
-      helper.getDecoratedStart(maxPosView));
-    int end = Math.max(helper.getDecoratedEnd(minPosView),
-      helper.getDecoratedEnd(maxPosView));
+    int start = Math.min(helper.getDecoratedStart(minPosView), helper.getDecoratedStart(maxPosView));
+    int end = Math.max(helper.getDecoratedEnd(minPosView), helper.getDecoratedEnd(maxPosView));
     int distance = end - start;
     if (distance == 0) {
       return INVALID_DISTANCE;
@@ -632,16 +551,7 @@ public class MainCategorySnapper extends RecyclerView.OnFlingListener {
   }
 
   @NonNull
-  private OrientationHelper getVerticalHelper(@NonNull LayoutManager layoutManager) {
-    if (mVerticalHelper == null || mVerticalHelper.getLayoutManager() != layoutManager) {
-      mVerticalHelper = OrientationHelper.createVerticalHelper(layoutManager);
-    }
-    return mVerticalHelper;
-  }
-
-  @NonNull
-  private OrientationHelper getHorizontalHelper(
-    @NonNull LayoutManager layoutManager) {
+  private OrientationHelper getHorizontalHelper(@NonNull LayoutManager layoutManager) {
     if (mHorizontalHelper == null || mHorizontalHelper.getLayoutManager() != layoutManager) {
       mHorizontalHelper = OrientationHelper.createHorizontalHelper(layoutManager);
     }

+ 0 - 1
app/src/main/java/kr/co/zumo/app/lifeplus/view/screen/main/MainContentsSnapper.java

@@ -512,7 +512,6 @@ public class MainContentsSnapper extends RecyclerView.OnFlingListener {
     }
 
     int vDeltaJump;
-
     vDeltaJump = estimateNextPositionDiffForFling(layoutManager, getVerticalHelper(layoutManager), 0, velocityY);
     if (vectorForEnd.y < 0) {
       vDeltaJump = -vDeltaJump;