正方形の画像でグリッドレイアウトを作成しようとしています。 GridLayoutManager
を操作してonMeasure
を操作することが可能でなければならないと考えました
super.onMeasure(recycler, state, widthSpec, widthSpec);
の代わりに
super.onMeasure(recycler, state, widthSpec, heightSpec);
しかし、残念ながら、それはうまくいきませんでした。
何か案は?
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
)。
制約レイアウトはこの問題を解決します。つかいます 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>
誰かが異なる方法でビューを拡大したい場合-これがあなたのやり方です:
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);
}
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"
はここのキー属性です
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>
繰り返しますが、比較的最近の「パーセント」レイアウトをお勧めします。依存関係の使用'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よりはるかに高速です。
私は選択した答えが好きではないので、私のものを提供しましょう: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;
}
それはうまくいくようです。
誤解しないでください、これも非常に厄介ですが、少なくともこのソリューションはビュー階層を拡張することでアプリのパフォーマンスを損ないません
私は同様の問題を抱えていたので、リサイクラービューのグリッドで正方形になるビューを膨らませる必要がありました。以下は私のやり方です。
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);
}
});