web-dev-qa-db-ja.com

RecyclerViewのGridLayoutManager上の正方形レイアウト

正方形の画像でグリッドレイアウトを作成しようとしています。 GridLayoutManagerを操作してonMeasureを操作することが可能でなければならないと考えました

super.onMeasure(recycler, state, widthSpec, widthSpec); 

の代わりに

super.onMeasure(recycler, state, widthSpec, heightSpec);

しかし、残念ながら、それはうまくいきませんでした。

何か案は?

58
Paul Woitaschek

RecyclerViewに正方形要素を含めるために、ルートビュー要素の単純なラッパーを提供します。 SquareRelativeLayoutの代わりに次のRelativeLayoutを使用します。

package net.simplyadvanced.widget;

import Android.content.Context;
import Android.util.AttributeSet;
import Android.widget.RelativeLayout;

/** A RelativeLayout that will always be square -- same width and height,
 * where the height is based off the width. */
public class SquareRelativeLayout extends RelativeLayout {

    public SquareRelativeLayout(Context context) {
        super(context);
    }

    public SquareRelativeLayout(Context context, AttributeSet attrs) {
        super(context, attrs);
    }

    public SquareRelativeLayout(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
    }

    @TargetApi(VERSION_CODES.Lollipop)
    public SquareRelativeLayout(Context context, AttributeSet attrs,         int defStyleAttr, int defStyleRes) {
        super(context, attrs, defStyleAttr, defStyleRes);
    }

    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        // Set a square layout.
        super.onMeasure(widthMeasureSpec, widthMeasureSpec);
    }

}

次に、アダプターのXMLレイアウトで、次のようにカスタムビューを参照しました。ただし、これはプログラムで行うこともできます。

<?xml version="1.0" encoding="utf-8"?>
<net.simplyadvanced.widget.SquareRelativeLayout
    xmlns:Android="http://schemas.Android.com/apk/res/Android"
    Android:id="@+id/elementRootView"
    Android:layout_width="wrap_content"
    Android:layout_height="wrap_content">

    <!-- More widgets here. -->

</net.simplyadvanced.widget.SquareRelativeLayout>

注:グリッドの向きに応じて、高さ(GridLayoutManager.HORIZONTAL)高さの代わりに幅(GridLayoutManager.VERTICAL)。

150
Anonsage

制約レイアウトはこの問題を解決します。つかいます app:layout_constraintDimensionRatio="H,1:1"

recyclerview_grid_layout.xml

<Android.support.constraint.ConstraintLayout
    Android:layout_width="match_parent"
    Android:layout_height="wrap_content"
    xmlns:Android="http://schemas.Android.com/apk/res/Android"
    xmlns:app="http://schemas.Android.com/apk/res-auto">

    <ImageView
        Android:id="@+id/imageview"
        Android:layout_width="match_parent"
        Android:layout_height="0dp"
        app:layout_constraintDimensionRatio="H,1:1"
        Android:scaleType="centerCrop"
        app:layout_constraintTop_toTopOf="parent"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintLeft_toLeftOf="parent"
        app:layout_constraintRight_toRightOf="parent"/>

</Android.support.constraint.ConstraintLayout>
53
veritas1

誰かが異なる方法でビューを拡大したい場合-これがあなたのやり方です:

private static final double WIDTH_RATIO = 3;
private static final double HEIGHT_RATIO = 4;
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
    int widthSize = MeasureSpec.getSize(widthMeasureSpec);
    int heightSize = (int) (HEIGHT_RATIO / WIDTH_RATIO * widthSize);
    int newHeightSpec = MeasureSpec.makeMeasureSpec(heightSize, MeasureSpec.EXACTLY);
    super.onMeasure(widthMeasureSpec, newHeightSpec);
}
19
gswierczynski

API 26(サポートライブラリ26.0)以降、アスペクト比プロパティを公開するConstraintLayoutを使用して、ビューを2乗させることができます。 https://developer.Android.com/training/constraint-layout/index.htm =

Android {
    compileSdkVersion 26
    buildToolsVersion '26.0.2'
    ...
}
...
dependencies {
    compile 'com.Android.support:appcompat-v7:26.0.2'
    compile 'com.Android.support.constraint:constraint-layout:1.1.0-beta1' //use whatever version is current
}

GridLayoutManagerで使用しているレイアウトの例:

<?xml version="1.0" encoding="utf-8"?>
<Android.support.constraint.ConstraintLayout
    xmlns:Android="http://schemas.Android.com/apk/res/Android"
    xmlns:app="http://schemas.Android.com/apk/res-auto"
    Android:layout_width="match_parent"
    Android:layout_height="match_parent"
    Android:layout_margin="@dimen/margin_small"
    Android:background="@drawable/border_gray"
    Android:gravity="center">

    <Android.support.constraint.ConstraintLayout
        Android:layout_width="0dp"
        Android:layout_height="0dp"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintDimensionRatio="h,1:1"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent">

        <!-- place your content here -->


    </Android.support.constraint.ConstraintLayout>

</Android.support.constraint.ConstraintLayout>

app:layout_constraintDimensionRatio="h,1:1"はここのキー属性です

7
vir us

FrameLayoutのこの拡張機能を試してください。一貫性を向上させるために二重測定を実行します。また、レイアウトから必要なアスペクト比を設定するためのカスタムXMLプロパティもサポートしています

public class StableAspectFrameLayout extends FrameLayout {

    private int aspectWidth = 1;
    private int aspectHeight = 1;

    public StableAspectFrameLayout(Context context) {
        this(context, null, 0);
    }

    public StableAspectFrameLayout(Context context, AttributeSet attrs) {
        this(context, attrs, 0);
    }

    public StableAspectFrameLayout(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        extractCustomAttrs(context, attrs);
    }

    @TargetApi(Build.VERSION_CODES.Lollipop)
    public StableAspectFrameLayout(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
        super(context, attrs, defStyleAttr, defStyleRes);
        extractCustomAttrs(context, attrs);
    }

    private void extractCustomAttrs(Context context, AttributeSet attrs) {
        if (attrs == null) return;
        TypedArray a = context.getResources().obtainAttributes(attrs, R.styleable.StableAspectFrameLayout);
        try {
            aspectWidth = a.getInteger(R.styleable.StableAspectFrameLayout_aspect_width, 1);
            aspectHeight = a.getInteger(R.styleable.StableAspectFrameLayout_aspect_height, 1);
        } finally {
            a.recycle();
        }
    }

    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        super.onMeasure(widthMeasureSpec, heightMeasureSpec);

        int newSpecWidth = MeasureSpec.makeMeasureSpec(getMeasuredWidth(), MeasureSpec.EXACTLY);
        int newH = Math.round(((float) getMeasuredWidth()) * aspectHeight / aspectWidth);
        int newSpecHeigh = MeasureSpec.makeMeasureSpec(newH, MeasureSpec.EXACTLY);
        super.onMeasure(newSpecWidth, newSpecHeigh);
    }
}

そして、attrs.xmlのコンテンツ

<?xml version="1.0" encoding="utf-8"?>
<resources>
    <!--  StableAspectFrameLayout  -->
    <declare-styleable name="StableAspectFrameLayout">
        <attr name="aspect_width" format="integer"/>
        <attr name="aspect_height" format="integer"/>
    </declare-styleable>

</resources>
3

繰り返しますが、比較的最近の「パーセント」レイアウトをお勧めします。依存関係の使用'com.Android.support:percent:25.2.0'、次のようなことができます。

<Android.support.percent.PercentFrameLayout
      Android:layout_width="match_parent"
      Android:layout_height="wrap_content">
      <ImageView
         Android:id="@+id/image"
         app:layout_widthPercent="100%"
         app:layout_aspectRatio="100%"
         Android:padding="10dp"
         Android:scaleType="centerCrop"
         Android:cropToPadding="true"
         tools:background="#efdbed"
         />
   </Android.support.percent.PercentFrameLayout>

おそらくいつかはもう気にしないかもしれませんが、おそらくConstraintLayoutよりはるかに高速です。

1
androidguy

私は選択した答えが好きではないので、私のものを提供しましょう:SomeDammyLayoutWithFixedAspectRatioでアイテムレイアウト全体をラップする代わりに、GridLayoutManagerをハックしてmeasureChild内のコードを書き換えることができます。私はこれらの行を置き換えました:

if (mOrientation == VERTICAL) {
        wSpec = getChildMeasureSpec(availableSpaceInOther, otherDirParentSpecMode,
                horizontalInsets, lp.width, false);
        hSpec = getChildMeasureSpec(mOrientationHelper.getTotalSpace(), getHeightMode(),
                verticalInsets, lp.height, true);
    } else {
        hSpec = getChildMeasureSpec(availableSpaceInOther, otherDirParentSpecMode,
                verticalInsets, lp.height, false);
        wSpec = getChildMeasureSpec(mOrientationHelper.getTotalSpace(), getWidthMode(),
                horizontalInsets, lp.width, true);
    }

に:

if (mOrientation == VERTICAL) {
        wSpec = getChildMeasureSpec(availableSpaceInOther, otherDirParentSpecMode,
                horizontalInsets, lp.width, false);
        hSpec = wSpec;
    } else {
        hSpec = getChildMeasureSpec(availableSpaceInOther, otherDirParentSpecMode,
                verticalInsets, lp.height, false);
        wSpec = hSpec;
    }

それはうまくいくようです。

誤解しないでください、これも非常に厄介ですが、少なくともこのソリューションはビュー階層を拡張することでアプリのパフォーマンスを損ないません

0
Karma Maker

私は同様の問題を抱えていたので、リサイクラービューのグリッドで正方形になるビューを膨らませる必要がありました。以下は私のやり方です。

OnCreateViewHolderメソッド内で、ViewTreeObserverとGlobalLayoutListenerを使用して、レイアウトの測定幅を取得しました。レイアウトのwidth属性にmatch_parent値があります。私のリサイクラビューはすべて、中央が水平にレイアウトされています。

final View view = LayoutInflater.from(mActivity).inflate(R.layout.list_item_deals, parent, false);
    view.getViewTreeObserver().addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {
        @Override
        public void onGlobalLayout() {
            int side = view.getMeasuredWidth();

            ViewGroup.LayoutParams lp = view.getLayoutParams();
            lp.width = side;
            lp.height = side;
            view.setLayoutParams(lp);
        }
    });

参照画像

0
user8646587