ImageView - 高度是否与宽度匹配?

216

我有一个ImageView,我希望它的宽度填满父容器。我希望其高度与最终的宽度相同。例如:

<ImageView
  android:layout_width="fill_parent"
  android:layout_height="whatever the width ends up being" />

在不创建自定义视图类的情况下,是否可以在布局文件中实现这样的操作?

谢谢


你弄明白怎么做了吗?我猜你想保持纵横比不变。大多数答案都假设你想让图像是正方形的。 - Adam
@Joe Blow,那是一种非常糟糕的做法。 - Aggressor
14个回答

254

2021年7月28日更新,使用AndroidX而不是支持库

首先,请按照这里的说明导入AndroidX到您的项目中。

然后将您的图像包装在ConstraintLayout内,并设置其字段如下:

<androidx.constraintlayout.widget.ConstraintLayout
    android:layout_width="match_parent"
    android:layout_height="wrap_content">

    <ImageView
        android:layout_width="wrap_content"
        android:layout_height="0dp"
        app:layout_constraintDimensionRatio="1:1" />

</androidx.constraintlayout.widget.ConstraintLayout>

请在这里查看


9
这个答案中提供的最优雅的解决方案来自Google。在我的情况下,我希望图片以16:9的比例显示,无论原始图片的宽高比如何。效果很好。谢谢! - Eddie
5
别忘了在你的依赖中添加'compile com.android.support:percent:23.3.0'。 - Milad Faridnia
这似乎是因为 WrappedViewPager 存在问题,它根据其子内容计算高度。类似于 https://gist.github.com/egslava/589b82a6add9c816a007 的 WrappedViewPager 源代码。 - sha
1
自Android支持库26.0.0起,“Percent Support”模块已被弃用。来源:https://developer.android.com/topic/libraries/support-library/revisions.html#26-0-0 - MHogge
如果我不使用 Constraint Layout 呢? - Kakaji
显示剩余4条评论

116

也许这能回答你的问题:

<ImageView
    android:id="@+id/cover_image"
    android:layout_width="fill_parent"
    android:layout_height="wrap_content"
    android:scaleType="fitCenter"
    android:adjustViewBounds="true" />

对于这种情况,您可以忽略scaleType属性。


5
不一定是无用的。这对我的使用很好,我有一个图标在标题栏上,我想将其缩放以填充高度,同时保持正方形。 - Anubian Noob
4
我的问题也得到了解决。 - Dielson Sales
1
最简单的方法!应该将其标记为最佳答案。 - HF_

31

可以使用LayoutParams来动态设置View的高度,一旦您在运行时了解了View的宽度。您需要使用一个Runnable线程来获取运行时视图的宽度,否则您将尝试在了解视图宽度之前设置高度,因为布局尚未绘制。

以下是我解决问题的示例:

final FrameLayout mFrame = (FrameLayout) findViewById(R.id.frame_id);

    mFrame.post(new Runnable() {

        @Override
        public void run() {
            RelativeLayout.LayoutParams mParams;
            mParams = (RelativeLayout.LayoutParams) mFrame.getLayoutParams();
            mParams.height = mFrame.getWidth();
            mFrame.setLayoutParams(mParams);
            mFrame.postInvalidate();
        }
    });

LayoutParams必须是您的视图所在的父视图类型。我的FrameLayout在xml文件中放置在RelativeLayout中。

    mFrame.postInvalidate();

调用此方法将强制视图在与 UI 线程不同的线程上重新绘制。


4
非常棒的答案,特别是关于Runnable的部分,谢谢! - jesses.co.tt
1
虽然这样可以工作,但并不理想。在 post 上运行意味着视图在布局更改之前只渲染一次。可能会在错误的高度上闪现内容,然后才正确绘制。最好尽早解决。最早解决的时刻是在自定义 onMeasure 期间,如 Regis' answer 中所示。另一种方法,但仅适用于通过适配器呈现的视图,例如 GridView 内部的视图,是 Matt's answer - ToolmakerSteve
1
只有在设置参数后调用 requestLayout() 才对我起作用了。这是为什么呢? - Divins Mathew
mFrame.postInvalidate();就是它所做的,没有它,我得到的视图位置不正确。 - Jacolack

20

我无法使David Chu的答案在RecyclerView项目中工作,并且发现我需要将ImageView约束到其父视图。将ImageView宽度设置为0dp,并将其开始和结束约束到父视图。我不确定在某些情况下是否将宽度设置为wrap_contentmatch_parent会起作用,但我认为这是获取ConstraintLayout的子项填充其父项的更好方法。

<androidx.constraintlayout.widget.ConstraintLayout
    android:layout_width="match_parent"
    android:layout_height="wrap_content">

    <ImageView
        android:layout_width="0dp"
        android:layout_height="0dp"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintDimensionRatio="1:1"/>

</androidx.constraintlayout.widget.ConstraintLayout>

15

如果您的图像视图在一个约束布局中,您可以使用以下约束条件创建一个正方形的图像视图,请确保使用1:1来创建正方形

<ImageView
    android:layout_width="0dp"
    android:layout_height="0dp"
    android:id="@+id/ivImageView"
    app:layout_constraintDimensionRatio="1:1"
    app:layout_constraintStart_toStartOf="parent"
    app:layout_constraintEnd_toEndOf="parent"/>

13

下面是我为了获得一个始终宽度等于高度的ImageButton而做的事情(并避免在一个方向上出现愚蠢的空白边距......我认为这是SDK的一个错误):

我定义了一个SquareImageButton类,它继承自ImageButton:

package com.myproject;

import android.content.Context;
import android.util.AttributeSet;
import android.util.Log;
import android.widget.ImageButton;

    public class SquareImageButton extends ImageButton {

        public SquareImageButton(Context context) {
        super(context);


        // TODO Auto-generated constructor stub
    }

    public SquareImageButton(Context context, AttributeSet attrs) {
        super(context, attrs);
        // TODO Auto-generated constructor stub

    }

    public SquareImageButton(Context context, AttributeSet attrs, int defStyle) {
        super(context, attrs, defStyle);
        // TODO Auto-generated constructor stub

    }

    int squareDim = 1000000000;

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


        int h = this.getMeasuredHeight();
        int w = this.getMeasuredWidth();
        int curSquareDim = Math.min(w, h);
        // Inside a viewholder or other grid element,
        // with dynamically added content that is not in the XML,
        // height may be 0.
        // In that case, use the other dimension.
        if (curSquareDim == 0)
            curSquareDim = Math.max(w, h);

        if(curSquareDim < squareDim)
        {
            squareDim = curSquareDim;
        }

        Log.d("MyApp", "h "+h+"w "+w+"squareDim "+squareDim);


        setMeasuredDimension(squareDim, squareDim);

    }

}

这是我的 XML:

<com.myproject.SquareImageButton
            android:id="@+id/speakButton"
            android:layout_width="wrap_content"
            android:layout_height="match_parent"
            android:scaleType="centerInside"
            android:src="@drawable/icon_rounded_no_shadow_144px"
            android:background="#00ff00"
            android:layout_alignTop="@+id/searchEditText"
            android:layout_alignBottom="@+id/searchEditText"
            android:layout_alignParentLeft="true"
           />

运作得非常好!


是的,这是最好的答案。(也是唯一真正符合提问者问题的答案) - Twometer

6
在Android 26.0.0中,PercentRelativeLayout已被弃用
现在最好的解决方法是使用ConstraintLayout,就像这样:
<android.support.constraint.ConstraintLayout
                    android:layout_width="match_parent"
                    android:layout_height="wrap_content">

    <ImageView android:layout_width="match_parent"
               android:layout_height="0dp"
               android:scaleType="centerCrop"
               android:src="@drawable/you_image"                       
               app:layout_constraintDimensionRatio="1:1"/>


</android.support.constraint.ConstraintLayout>


这里是一份关于如何将ConstraintLayout添加到您的项目中的教程


6
您无法仅通过布局来实现它,我已经尝试过了。最终我编写了一个非常简单的类来处理它,您可以在Github上查看。 SquareImage.java 它是一个更大项目的一部分,但只需复制粘贴即可解决问题(根据Apache 2.0许可证)。
基本上,您只需要将高度/宽度设置为另一个维度相等(取决于您想要缩放的方式)。
注意:您可以使用“scaleType”属性使其成为正方形,但视图的边界超出可见图像,如果您将其他视图放置在其附近,则会引起问题。

6
要将您的ImageView设置为屏幕的一半大小,您需要在ImageView的XML中添加以下内容:
<ImageView
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:layout_centerInParent="true"
    android:scaleType="fitXY"
    android:adjustViewBounds="true"/>

要将高度设置为宽度大小,您需要在代码中进行设置。在您的GridView适配器的getView方法中,将ImageView的高度设置为其测量宽度:

mImageView.getLayoutParams().height = mImageView.getMeasuredWidth();

4

现在对于路过的人,在2017年,实现你想要的最佳方式是像这样使用ConstraintLayout

<ImageView
    android:layout_width="0dp"
    android:layout_height="0dp"
    android:scaleType="centerCrop"
    app:layout_constraintDimensionRatio="1:1" />

不要忘记根据您的布局需要为所有四个方向添加约束。

使用ConstraintLayout构建响应式UI

此外,现在已经弃用了PercentRelativeLayout(请参见Android文档)。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接