用于RecyclerView的GridLayoutManager上的方形布局
我尝试使用方形图像进行网格布局。 我认为,通过操纵onMeasure
来操作GridLayoutManager
一定是可能的
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布局中,我刚刚引用了自定义视图,如下所示。 尽pipe如此,你也可以通过编程来完成这个任务
<?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
)的高度。
如果有人想以不同的方式缩放视图 – 这是你如何做到这一点:
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); }
约束布局解决了这个问题。 使用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>
请试试这个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快得多,但有一天我们可能不会在意了。
启动API 26(支持库26.0),可以使用公开宽高比属性强制视图平方的ConstraintLayout: 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"
是这里的关键属性
我不喜欢select的答案,所以让我提供我的:而不是包装在SomeDammyLayoutWithFixedAspectRatio整个项目布局,你可以砍掉GridLayoutManager,并重写measureChild内的代码。 我已经replace了这些行:
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; }
它似乎工作正常。
不要误解我的意思,这也太乱了,但至less这个解决scheme不会通过扩展视图层次来伤害应用的性能
- 如何使用ArrayList <Parcelable>正确实现Parcelable?
- 如何监视SIM状态变化
- 隐藏HorizontalScrollView的滚动条
- Android CollapsingToolbarLayout折叠监听器
- “为此应用评分” – 在手机上的Google Play商店应用中链接
- 如何使用Volley在Android中发送“multipart / form-data”POST
- 为什么构buildtypes不同于产品口味?
- 如何正确地从Android上使用Gradle构build文件从org.apache导入HttpClient?
- 在Android中,如何以编程方式在dp中设置页边距?