Skip to content

Instantly share code, notes, and snippets.

@heruoxin
Last active January 10, 2020 07:50
Show Gist options
  • Save heruoxin/51b8975676b5d9f1a1964afd3ce0c5b7 to your computer and use it in GitHub Desktop.
Save heruoxin/51b8975676b5d9f1a1964afd3ce0c5b7 to your computer and use it in GitHub Desktop.
修复当 RecyclerView 被其他透明或半透明 View 遮挡时,LinearLayoutManager#findFirstVisibleItemPosition 等方法会失效的问题。
import android.annotation.SuppressLint;
import android.content.Context;
import android.util.AttributeSet;
import android.view.View;
import java.util.HashMap;
import java.util.Map;
import androidx.annotation.Nullable;
import androidx.recyclerview.widget.LinearLayoutManager;
import androidx.recyclerview.widget.RecyclerView;
/**
* @author heruoxin @ CatchingNow Inc.
* @since 2019-08-04
*/
public class AdvancedLinearLayoutManager extends LinearLayoutManager {
@Nullable
private RecyclerView rv;
public AdvancedLinearLayoutManager(Context context) {
super(context);
}
public AdvancedLinearLayoutManager(Context context, int orientation, boolean reverseLayout) {
super(context, orientation, reverseLayout);
}
public AdvancedLinearLayoutManager(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
super(context, attrs, defStyleAttr, defStyleRes);
}
@Override
public void onAttachedToWindow(RecyclerView view) {
super.onAttachedToWindow(view);
rv = view;
}
@Override
public void onDetachedFromWindow(RecyclerView view, RecyclerView.Recycler recycler) {
super.onDetachedFromWindow(view, recycler);
rv = null;
}
// map of child adapter position to its height.
@SuppressLint("UseSparseArrays")
private Map<Integer, Integer> childSizesMap = new HashMap<>();
@Override
public void onLayoutCompleted(RecyclerView.State state) {
super.onLayoutCompleted(state);
for (int i = 0; i < getChildCount(); i++) {
View child = getChildAt(i);
if (child != null) childSizesMap.put(getPosition(child), getDecoratedMeasuredHeight(child));
}
}
@Override
public int computeVerticalScrollOffset(RecyclerView.State state) {
//return super.computeVerticalScrollOffset(state);
if (getChildCount() == 0) return 0;
int firstChildPosition = findFirstVisibleItemPosition();
View firstChild = findViewByPosition(firstChildPosition);
if (firstChild == null) return super.computeVerticalScrollOffset(state);
int scrolledY = - getDecoratedTop(firstChild);
for (int i = 0; i < firstChildPosition; i++) {
Integer size = childSizesMap.get(i);
scrolledY += size != null ? size : 0;
}
return scrolledY + getPaddingTop();
}
private int calcItemPosition(Operator operator) {
if (rv == null) return RecyclerView.NO_POSITION;
boolean vertical = getOrientation() == RecyclerView.VERTICAL;
int length = vertical ? rv.getHeight() : rv.getWidth();
int paddingStart = vertical ? rv.getPaddingTop() : rv.getPaddingStart();
int paddingEnd = vertical ? rv.getPaddingBottom() : rv.getPaddingEnd();
View item = null;
for (int i = 0; i < rv.getChildCount(); i++) {
item = operator.apply(vertical, paddingStart, paddingEnd, length, rv.getChildAt(i), item);
}
if (item == null) return RecyclerView.NO_POSITION;
return getPosition(item);
}
private interface Operator {
View apply(boolean vertical,int paddingStart, int paddingEnd, int length, View v1, View v2);
}
@Override
public int findFirstVisibleItemPosition() {
return findFirstVisibleItemPosition(false);
}
public int findFirstVisibleItemPosition(boolean ignorePadding) {
return calcItemPosition((vertical, paddingStart, paddingEnd, length, v1, v2) -> {
int actuallyLength = ignorePadding ? 0 : paddingStart;
float v1Position = v1 == null ? Float.MAX_VALUE : (vertical ? v1.getY() + v1.getHeight() : v1.getX() + v1.getWidth());
float v2Position = v2 == null ? Float.MAX_VALUE : (vertical ? v2.getY() + v2.getHeight() : v2.getX() + v2.getWidth());
v1Position = v1Position < actuallyLength ? Float.MAX_VALUE : v1Position;
v2Position = v2Position < actuallyLength ? Float.MAX_VALUE : v2Position;
return v1Position < v2Position ? v1 : v2;
});
}
@Override
public int findFirstCompletelyVisibleItemPosition() {
return findFirstCompletelyVisibleItemPosition(false);
}
public int findFirstCompletelyVisibleItemPosition(boolean ignorePadding) {
return calcItemPosition((vertical, paddingStart, paddingEnd, length, v1, v2) -> {
int actuallyLength = ignorePadding ? 0 : paddingStart;
float v1Position = v1 == null ? Float.MAX_VALUE : (vertical ? v1.getY() : v1.getX());
float v2Position = v2 == null ? Float.MAX_VALUE : (vertical ? v2.getY() : v2.getX());
v1Position = v1Position < actuallyLength ? Float.MAX_VALUE : v1Position;
v2Position = v2Position < actuallyLength ? Float.MAX_VALUE : v2Position;
return v1Position < v2Position ? v1 : v2;
});
}
@Override
public int findLastVisibleItemPosition() {
return findLastVisibleItemPosition(false);
}
public int findLastVisibleItemPosition(boolean ignorePadding) {
return calcItemPosition((vertical, paddingStart, paddingEnd, length, v1, v2) -> {
int actuallyLength = ignorePadding ? length : length - paddingEnd;
float v1Position = v1 == null ? Float.MIN_VALUE : (vertical ? v1.getY() : v1.getX());
float v2Position = v2 == null ? Float.MIN_VALUE : (vertical ? v2.getY() : v2.getX());
v1Position = v1Position > actuallyLength ? Float.MIN_VALUE : v1Position;
v2Position = v2Position > actuallyLength ? Float.MIN_VALUE : v2Position;
return v1Position > v2Position ? v1 : v2;
});
}
@Override
public int findLastCompletelyVisibleItemPosition() {
return findLastCompletelyVisibleItemPosition(false);
}
public int findLastCompletelyVisibleItemPosition(boolean ignorePadding) {
return calcItemPosition((vertical, paddingStart, paddingEnd, length, v1, v2) -> {
int actuallyLength = ignorePadding ? length : length - paddingEnd;
float v1Position = v1 == null ? Float.MIN_VALUE : (vertical ? v1.getY() + v1.getHeight() : v1.getX() + v1.getWidth());
float v2Position = v2 == null ? Float.MIN_VALUE : (vertical ? v2.getY() + v2.getHeight() : v2.getX() + v2.getWidth());
v1Position = v1Position > actuallyLength ? Float.MIN_VALUE : v1Position;
v2Position = v2Position > actuallyLength ? Float.MIN_VALUE : v2Position;
return v1Position > v2Position ? v1 : v2;
});
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment