スクロール中にズームのような効果を得るために、画面中央のアイテムビューのサイズを変更する垂直リサイクラビューを作成する必要があります。
私が試したがうまくいかなかったこと:
スクロールリスナーを追加し、位置ごとにアイテムビューをループし、中心位置を測定してから、中心LayoutParams
のview
を更新します。
RecyclerView
は、スクロール中にアイテムの位置を計算したり、ビューを更新したりしません。そのような操作がIllegalStateException
で実行される場合、onScrolled
をスローします。スクロール状態がLayoutParams
またはonScrollStateChanged
であるときに、IDLE
の中央のアイテムビューのSETTLING
を変更します。
最後に残ったオプションは、デフォルトのLayoutManager
を拡張する独自のカスタムLayoutManager
を実装することです。
Layoutmanager
の実装には、処理が必要なはるかに複雑な計算の処理が含まれます。他のソリューションやアイデアは歓迎されます。
私は SOに関するこの答え を見つけました。これはまったく同じことを水平に行いました。 Answerは、LinearLayoutManager
を拡張する実用的なソリューションを提供します。また、垂直リストを適応させるために少し変更しましたが、動作します。実装に誤りがある場合は、コメントでお知らせください。乾杯!
カスタムレイアウトマネージャー:
public class CenterZoomLayoutManager extends LinearLayoutManager {
private final float mShrinkAmount = 0.15f;
private final float mShrinkDistance = 0.9f;
public CenterZoomLayoutManager(Context context) {
super(context);
}
public CenterZoomLayoutManager(Context context, int orientation, boolean reverseLayout) {
super(context, orientation, reverseLayout);
}
@Override
public int scrollVerticallyBy(int dy, RecyclerView.Recycler recycler, RecyclerView.State state) {
int orientation = getOrientation();
if (orientation == VERTICAL) {
int scrolled = super.scrollVerticallyBy(dy, recycler, state);
float midpoint = getHeight() / 2.f;
float d0 = 0.f;
float d1 = mShrinkDistance * midpoint;
float s0 = 1.f;
float s1 = 1.f - mShrinkAmount;
for (int i = 0; i < getChildCount(); i++) {
View child = getChildAt(i);
float childMidpoint =
(getDecoratedBottom(child) + getDecoratedTop(child)) / 2.f;
float d = Math.min(d1, Math.abs(midpoint - childMidpoint));
float scale = s0 + (s1 - s0) * (d - d0) / (d1 - d0);
child.setScaleX(scale);
child.setScaleY(scale);
}
return scrolled;
} else {
return 0;
}
}
@Override
public int scrollHorizontallyBy(int dx, RecyclerView.Recycler recycler, RecyclerView.State state) {
int orientation = getOrientation();
if (orientation == HORIZONTAL) {
int scrolled = super.scrollHorizontallyBy(dx, recycler, state);
float midpoint = getWidth() / 2.f;
float d0 = 0.f;
float d1 = mShrinkDistance * midpoint;
float s0 = 1.f;
float s1 = 1.f - mShrinkAmount;
for (int i = 0; i < getChildCount(); i++) {
View child = getChildAt(i);
float childMidpoint =
(getDecoratedRight(child) + getDecoratedLeft(child)) / 2.f;
float d = Math.min(d1, Math.abs(midpoint - childMidpoint));
float scale = s0 + (s1 - s0) * (d - d0) / (d1 - d0);
child.setScaleX(scale);
child.setScaleY(scale);
}
return scrolled;
} else {
return 0;
}
}
}
垂直方向の場合: