来几个稀里糊涂的 CV
//https://www.jianshu.com/p/ef3a3b8d0a77
//https://www.jianshu.com/p/e54db232df62
1.一次只能最多翻过一页的SnapHelper
public class GallerySnapHelper extends SnapHelper {
private static final float INVALID_DISTANCE = 1f;
private static final float MILLISECONDS_PER_INCH = 40f;
private OrientationHelper mHorizontalHelper;
private RecyclerView mRecyclerView;
@Override
public void attachToRecyclerView(@Nullable RecyclerView recyclerView) throws IllegalStateException {
mRecyclerView = recyclerView;
super.attachToRecyclerView(recyclerView);
}
@Override
public int[] calculateDistanceToFinalSnap(@NonNull RecyclerView.LayoutManager layoutManager, @NonNull View targetView) {
int[] out = new int[2];
if (layoutManager.canScrollHorizontally()) {
out[0] = distanceToStart(targetView, getHorizontalHelper(layoutManager));
} else {
out[0] = 0;
}
return out;
}
private int distanceToStart(View targetView, OrientationHelper helper) {
return helper.getDecoratedStart(targetView) - helper.getStartAfterPadding();
}
@Nullable
protected LinearSmoothScroller createSnapScroller(final RecyclerView.LayoutManager layoutManager) {
if (!(layoutManager instanceof RecyclerView.SmoothScroller.ScrollVectorProvider)) {
return null;
}
return new LinearSmoothScroller(mRecyclerView.getContext()) {
@Override
protected void onTargetFound(View targetView, RecyclerView.State state, Action action) {
int[] snapDistances = calculateDistanceToFinalSnap(mRecyclerView.getLayoutManager(), targetView);
final int dx = snapDistances[0];
final int dy = snapDistances[1];
final int time = calculateTimeForDeceleration(Math.max(Math.abs(dx), Math.abs(dy)));
if (time > 0) {
action.update(dx, dy, time, mDecelerateInterpolator);
}
}
@Override
protected float calculateSpeedPerPixel(DisplayMetrics displayMetrics) {
return MILLISECONDS_PER_INCH / displayMetrics.densityDpi;
}
};
}
@Override
public int findTargetSnapPosition(RecyclerView.LayoutManager layoutManager, int velocityX, int velocityY) {
if (!(layoutManager instanceof RecyclerView.SmoothScroller.ScrollVectorProvider)) {
return RecyclerView.NO_POSITION;
}
final int itemCount = layoutManager.getItemCount();
if (itemCount == 0) {
return RecyclerView.NO_POSITION;
}
final View currentView = findSnapView(layoutManager);
if (currentView == null) {
return RecyclerView.NO_POSITION;
}
final int currentPosition = layoutManager.getPosition(currentView);
if (currentPosition == RecyclerView.NO_POSITION) {
return RecyclerView.NO_POSITION;
}
RecyclerView.SmoothScroller.ScrollVectorProvider vectorProvider =
(RecyclerView.SmoothScroller.ScrollVectorProvider) layoutManager;
// deltaJumps sign comes from the velocity which may not match the order of children in
// the LayoutManager. To overcome this, we ask for a vector from the LayoutManager to
// get the direction.
PointF vectorForEnd = vectorProvider.computeScrollVectorForPosition(itemCount - 1);
if (vectorForEnd == null) {
// cannot get a vector for the given position.
return RecyclerView.NO_POSITION;
}
//在松手之后,列表最多只能滚多一屏的item数
int deltaThreshold = layoutManager.getWidth() / getHorizontalHelper(layoutManager).getDecoratedMeasurement(currentView);
int hDeltaJump;
if (layoutManager.canScrollHorizontally()) {
hDeltaJump = estimateNextPositionDiffForFling(layoutManager,
getHorizontalHelper(layoutManager), velocityX, 0);
if (hDeltaJump > deltaThreshold) {
hDeltaJump = deltaThreshold;
}
if (hDeltaJump < -deltaThreshold) {
hDeltaJump = -deltaThreshold;
}
if (vectorForEnd.x < 0) {
hDeltaJump = -hDeltaJump;
}
} else {
hDeltaJump = 0;
}
if (hDeltaJump == 0) {
return RecyclerView.NO_POSITION;
}
int targetPos = currentPosition + hDeltaJump;
if (targetPos < 0) {
targetPos = 0;
}
if (targetPos >= itemCount) {
targetPos = itemCount - 1;
}
return targetPos;
}
@Override
public View findSnapView(RecyclerView.LayoutManager layoutManager) {
return findStartView(layoutManager, getHorizontalHelper(layoutManager));
}
private View findStartView(RecyclerView.LayoutManager layoutManager, OrientationHelper helper) {
if (layoutManager instanceof LinearLayoutManager) {
int firstChildPosition = ((LinearLayoutManager) layoutManager).findFirstVisibleItemPosition();
if (firstChildPosition == RecyclerView.NO_POSITION) {
return null;
}
if (((LinearLayoutManager) layoutManager).findLastCompletelyVisibleItemPosition() == layoutManager.getItemCount() - 1) {
return null;
}
View firstChildView = layoutManager.findViewByPosition(firstChildPosition);
if (helper.getDecoratedEnd(firstChildView) >= helper.getDecoratedMeasurement(firstChildView) / 2 && helper.getDecoratedEnd(firstChildView) > 0) {
return firstChildView;
} else {
return layoutManager.findViewByPosition(firstChildPosition + 1);
}
} else {
return null;
}
}
private int estimateNextPositionDiffForFling(RecyclerView.LayoutManager layoutManager,
OrientationHelper helper, int velocityX, int velocityY) {
int[] distances = calculateScrollDistance(velocityX, velocityY);
float distancePerChild = computeDistancePerChild(layoutManager, helper);
if (distancePerChild <= 0) {
return 0;
}
int distance = distances[0];
if (distance > 0) {
return (int) Math.floor(distance / distancePerChild);
} else {
return (int) Math.ceil(distance / distancePerChild);
}
}
private float computeDistancePerChild(RecyclerView.LayoutManager layoutManager,
OrientationHelper helper) {
View minPosView = null;
View maxPosView = null;
int minPos = Integer.MAX_VALUE;
int maxPos = Integer.MIN_VALUE;
int childCount = layoutManager.getChildCount();
if (childCount == 0) {
return INVALID_DISTANCE;
}
for (int i = 0; i < childCount; i++) {
View child = layoutManager.getChildAt(i);
final int pos = layoutManager.getPosition(child);
if (pos == RecyclerView.NO_POSITION) {
continue;
}
if (pos < minPos) {
minPos = pos;
minPosView = child;
}
if (pos > maxPos) {
maxPos = pos;
maxPosView = child;
}
}
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 distance = end - start;
if (distance == 0) {
return INVALID_DISTANCE;
}
return 1f * distance / ((maxPos - minPos) + 1);
}
private OrientationHelper getHorizontalHelper(RecyclerView.LayoutManager layoutManager) {
if (mHorizontalHelper == null) {
mHorizontalHelper = OrientationHelper.createHorizontalHelper(layoutManager);
}
return mHorizontalHelper;
}
}
系统自带的
PagerSnapHelper LinearSnapHelper
public class MainActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
final RecyclerView mRecyclerview = findViewById(R.id.recyclerView);
List list=new ArrayList<>();
for (int i = 0; i < 20; i++) {
list.add(i+"");
}
SampleAdapter sampleAdapter = new SampleAdapter(R.layout.item_text, list);
mRecyclerview.setAdapter(sampleAdapter);
mRecyclerview.setLayoutManager(new LinearLayoutManager(this,LinearLayoutManager.HORIZONTAL,false));
mRecyclerview.smoothScrollToPosition(3);
//正常居中
// LinearSnapHelper linearSnapHelper = new LinearSnapHelper();
//左滑最多3个 右滑最多1个
// PagerSnapHelper pagerSnapHelper = new PagerSnapHelper();
GallerySnapHelper gallerySnapHelper = new GallerySnapHelper();
gallerySnapHelper.attachToRecyclerView(mRecyclerview);
mRecyclerview.addOnScrollListener(new RecyclerView.OnScrollListener() {
@Override
public void onScrolled(RecyclerView recyclerView, int dx, int dy) {
super.onScrolled(recyclerView, dx, dy);
int childCount = mRecyclerview.getChildCount();
int[] location = new int[2];
for (int i = 0; i < childCount; i++) {
View v = mRecyclerview.getChildAt(i);
v.getLocationOnScreen(location);
int recyclerViewCenterX = mRecyclerview.getLeft() + mRecyclerview.getWidth() / 2;
int itemCenterX = location[0] + v.getWidth() / 2;
// ★ 两边的图片缩放比例
float scale = 0.8f;
// ★某个item中心X坐标距recyclerview中心X坐标的偏移量
int offX = Math.abs(itemCenterX - recyclerViewCenterX);
// ★ 在一个item的宽度范围内,item从1缩放至scale,那么改变了(1-scale),从下列公式算出随着offX变化,item的变化缩放百分比
float percent =offX * (1 - scale) / v.getWidth();
// ★ 取反哟
float interpretateScale = 1 - percent;
// 这个if不走的话,得到的是多级渐变模式
if (interpretateScale < scale) {
interpretateScale = scale;
}
v.setScaleX((interpretateScale));
v.setScaleY((interpretateScale));
}
}
});
}
}