web-dev-qa-db-ja.com

リサイクルビュー-スクロール中のアイテムビューのサイズ変更(カルーセルのような効果の場合)

スクロール中にズームのような効果を得るために、画面中央のアイテムビューのサイズを変更する垂直リサイクラビューを作成する必要があります。

私が試したがうまくいかなかったこと:

  1. スクロールリスナーを追加し、位置ごとにアイテムビューをループし、中心位置を測定してから、中心LayoutParamsviewを更新します。

    • RecyclerViewは、スクロール中にアイテムの位置を計算したり、ビューを更新したりしません。そのような操作がIllegalStateExceptionで実行される場合、onScrolledをスローします。
  2. スクロール状態がLayoutParamsまたはonScrollStateChangedであるときに、IDLEの中央のアイテムビューのSETTLINGを変更します。

    • これは、アイテムのスクロール中に実行されているのではなく、スクロールが完了した/完了した後にのみビューを更新します。
  3. 最後に残ったオプションは、デフォルトのLayoutManagerを拡張する独自のカスタムLayoutManagerを実装することです。

    • 私の知る限り、カスタムLayoutmanagerの実装には、処理が必要なはるかに複雑な計算の処理が含まれます。

他のソリューションやアイデアは歓迎されます。

20
Krupal Shah

私は 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;
        }

    }
}

水平方向の場合: enter image description here

垂直方向の場合:

enter image description here

58
Krupal Shah