154 lines
6.6 KiB
Java
154 lines
6.6 KiB
Java
/*
|
|
* Copyright 2015 Hippo Seven
|
|
*
|
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
* you may not use this file except in compliance with the License.
|
|
* You may obtain a copy of the License at
|
|
*
|
|
* http://www.apache.org/licenses/LICENSE-2.0
|
|
*
|
|
* Unless required by applicable law or agreed to in writing, software
|
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
* See the License for the specific language governing permissions and
|
|
* limitations under the License.
|
|
*/
|
|
|
|
package com.hippo.easyrecyclerview;
|
|
|
|
import android.content.Context;
|
|
import android.graphics.PointF;
|
|
|
|
import androidx.recyclerview.widget.LinearLayoutManager;
|
|
import androidx.recyclerview.widget.RecyclerView;
|
|
import androidx.recyclerview.widget.StaggeredGridLayoutManager;
|
|
|
|
import com.hippo.yorozuya.MathUtils;
|
|
import com.hippo.yorozuya.SimpleHandler;
|
|
|
|
import java.lang.reflect.InvocationTargetException;
|
|
import java.lang.reflect.Method;
|
|
|
|
public final class LayoutManagerUtils {
|
|
|
|
private static Method sCsdfp = null;
|
|
|
|
static {
|
|
try {
|
|
sCsdfp = StaggeredGridLayoutManager.class.getDeclaredMethod("calculateScrollDirectionForPosition", int.class);
|
|
sCsdfp.setAccessible(true);
|
|
} catch (NoSuchMethodException e) {
|
|
// Ignore
|
|
e.printStackTrace();
|
|
}
|
|
}
|
|
|
|
public static void scrollToPositionWithOffset(
|
|
RecyclerView.LayoutManager layoutManager, int position, int offset) {
|
|
if (layoutManager instanceof LinearLayoutManager) {
|
|
((LinearLayoutManager) layoutManager).scrollToPositionWithOffset(position, offset);
|
|
} else if (layoutManager instanceof StaggeredGridLayoutManager) {
|
|
((StaggeredGridLayoutManager) layoutManager).scrollToPositionWithOffset(position, offset);
|
|
} else {
|
|
throw new IllegalStateException("Can't do scrollToPositionWithOffset for " +
|
|
layoutManager.getClass().getName());
|
|
}
|
|
}
|
|
|
|
public static void smoothScrollToPosition(
|
|
RecyclerView.LayoutManager layoutManager, Context context, int position) {
|
|
smoothScrollToPosition(layoutManager, context, position, -1);
|
|
}
|
|
|
|
public static void smoothScrollToPosition(
|
|
RecyclerView.LayoutManager layoutManager, Context context, int position,
|
|
int millisecondsPerInch) {
|
|
SimpleSmoothScroller smoothScroller;
|
|
if (layoutManager instanceof LinearLayoutManager) {
|
|
final LinearLayoutManager linearLayoutManager = (LinearLayoutManager) layoutManager;
|
|
smoothScroller = new SimpleSmoothScroller(context, millisecondsPerInch) {
|
|
@Override
|
|
public PointF computeScrollVectorForPosition(int targetPosition) {
|
|
return linearLayoutManager.computeScrollVectorForPosition(targetPosition);
|
|
}
|
|
};
|
|
|
|
} else if (layoutManager instanceof StaggeredGridLayoutManager) {
|
|
final StaggeredGridLayoutManager staggeredGridLayoutManager = (StaggeredGridLayoutManager) layoutManager;
|
|
smoothScroller = new SimpleSmoothScroller(context, millisecondsPerInch) {
|
|
@Override
|
|
public PointF computeScrollVectorForPosition(int targetPosition) {
|
|
int direction = 0;
|
|
try {
|
|
direction = (Integer) sCsdfp.invoke(staggeredGridLayoutManager, targetPosition);
|
|
} catch (IllegalAccessException | InvocationTargetException e) {
|
|
e.printStackTrace();
|
|
}
|
|
|
|
if (direction == 0) {
|
|
return null;
|
|
}
|
|
if (staggeredGridLayoutManager.getOrientation() == StaggeredGridLayoutManager.HORIZONTAL) {
|
|
return new PointF(direction, 0);
|
|
} else {
|
|
return new PointF(0, direction);
|
|
}
|
|
}
|
|
};
|
|
|
|
} else {
|
|
throw new IllegalStateException("Can't do smoothScrollToPosition for " +
|
|
layoutManager.getClass().getName());
|
|
}
|
|
smoothScroller.setTargetPosition(position);
|
|
layoutManager.startSmoothScroll(smoothScroller);
|
|
}
|
|
|
|
public static void scrollToPositionProperly(final RecyclerView.LayoutManager layoutManager,
|
|
final Context context, final int position, final OnScrollToPositionListener listener) {
|
|
SimpleHandler.getInstance().postDelayed(() -> {
|
|
int first = getFirstVisibleItemPosition(layoutManager);
|
|
int last = getLastVisibleItemPosition(layoutManager);
|
|
int offset = Math.abs(position - first);
|
|
int max = last - first;
|
|
if (offset < max && max > 0) {
|
|
smoothScrollToPosition(layoutManager, context, position,
|
|
MathUtils.lerp(100, 25, (offset / max)));
|
|
} else {
|
|
scrollToPositionWithOffset(layoutManager, position, 0);
|
|
if (listener != null) {
|
|
listener.onScrollToPosition(position);
|
|
}
|
|
}
|
|
}, 200);
|
|
}
|
|
|
|
public static int getFirstVisibleItemPosition(RecyclerView.LayoutManager layoutManager) {
|
|
if (layoutManager instanceof LinearLayoutManager) {
|
|
return ((LinearLayoutManager) layoutManager).findFirstVisibleItemPosition();
|
|
} else if (layoutManager instanceof StaggeredGridLayoutManager) {
|
|
int[] positions = ((StaggeredGridLayoutManager) layoutManager).findFirstVisibleItemPositions(null);
|
|
return MathUtils.min(positions);
|
|
} else {
|
|
throw new IllegalStateException("Can't do getFirstVisibleItemPosition for " +
|
|
layoutManager.getClass().getName());
|
|
}
|
|
}
|
|
|
|
public static int getLastVisibleItemPosition(RecyclerView.LayoutManager layoutManager) {
|
|
if (layoutManager instanceof LinearLayoutManager) {
|
|
return ((LinearLayoutManager) layoutManager).findLastVisibleItemPosition();
|
|
} else if (layoutManager instanceof StaggeredGridLayoutManager) {
|
|
int[] positions = ((StaggeredGridLayoutManager) layoutManager).findLastVisibleItemPositions(null);
|
|
return MathUtils.max(positions);
|
|
} else {
|
|
throw new IllegalStateException("Can't do getLastVisibleItemPosition for " +
|
|
layoutManager.getClass().getName());
|
|
}
|
|
}
|
|
|
|
public interface OnScrollToPositionListener {
|
|
void onScrollToPosition(int position);
|
|
}
|
|
}
|