【问题标题】:ImageView - have height match width?ImageView - 高度匹配宽度?
【发布时间】:2023-03-23 03:06:01
【问题描述】:

我有一个图像视图。我希望它的宽度是fill_parent。我希望它的高度是最终的宽度。例如:

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

在布局文件中是否有可能不需要创建自己的视图类?

谢谢

【问题讨论】:

  • 你知道怎么做吗?我假设您希望纵横比保持不变。这些答案中的大多数都假设您希望图像是方形的。
  • @Joe Blow 这是一种非常糟糕的做法

标签: android


【解决方案1】:

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

首先,按照here 的指示,确保您的项目已导入 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>

here

【讨论】:

  • 这个答案的链接有谷歌提供的最优雅的解决方案。就我而言,无论原始图像的纵横比是多少,我都希望图像以 16:9 的比例显示。效果很好。谢谢!
  • 我的情况是,this one 之类的解决方案不起作用,这个解决了!
  • 别忘了在你的依赖中添加'compile com.android.support:percent:23.3.0'
  • 看起来这种方法在 WrappedViewPager 上存在问题,它根据其子内容计算高度。 WrappedViewPager 的来源类似于gist.github.com/egslava/589b82a6add9c816a007
  • 百分比支持模块已被弃用自 android 支持库 26.0.0 以来已被弃用。来源:developer.android.com/topic/libraries/support-library/…
【解决方案2】:

也许这会回答你的问题:

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

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

【讨论】:

  • 它不一定没用。这对我的使用很好,我在标题栏上有一个图标,我想缩放以填充高度,同时保持正方形。
  • 也解决了我的问题。
  • 最简单的方法!这应该被标记为最佳答案。
【解决方案3】:

这可以使用 LayoutParams 在运行时知道视图宽度后动态设置视图高度来完成。您需要使用 Runnable 线程才能在运行时获取 View 的宽度,否则您将在知道 View 的宽度之前尝试设置 Height,因为尚未绘制布局。

我如何解决问题的示例:

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 线程不同的线程上时强制视图重绘

【讨论】:

  • 很棒的答案,尤其是 Runnable,谢谢!
  • 虽然这可行,但并不理想。在 post 上运行意味着视图在布局更改之前渲染一次。在正确绘制之前,可能会在错误的高度允许内容闪现。最好早点解决。最早可能解决的时间是在自定义onMeasure 期间,如Regis' answer 所示。另一种选择,但仅适用于通过适配器呈现的视图,例如在GridView 里面,是Matt's answer
  • 只有在设置参数后调用requestLayout() 后它才对我有用。为什么会这样?
  • mFrame.postInvalidate();是什么做的,没有它,我的视野就会错位。
【解决方案4】:

我无法让David Chu's answer 为 RecyclerView 项目工作,并发现我需要将 ImageView 限制为父项。将 ImageView 宽度设置为 0dp 并将其开始和结束限制为父级。我不确定将宽度设置为 wrap_contentmatch_parent 在某些情况下是否有效,但我认为这是让 ConstraintLayout 的子代填充其父代的更好方法。

<android.support.constraint.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"/>

</android.support.constraint.ConstraintLayout>

【讨论】:

    【解决方案5】:

    我在这里做了一个 ImageButton,它的宽度总是等于它的高度(并避免在一个方向上愚蠢的空白边距......我认为这是 SDK 的一个错误......):

    我定义了一个从 ImageButton 扩展而来的 SquareImageButton 类:

    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"
               />
    

    像魅力一样工作!

    【讨论】:

    • 是的,这是最好的答案。 (也是唯一一个真正符合 OP 问题的问题)
    【解决方案6】:

    如果您的图像视图在约束布局内,您可以使用以下约束来创建方形图像视图,确保使用 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"/>
    

    【讨论】:

      【解决方案7】:

      你不能只用布局来做到这一点,我试过了。我最终编写了一个非常简单的类来处理它,你可以在 github 上查看它。 SquareImage.java 它是一个更大项目的一部分,但没有什么是复制和粘贴无法修复的(在 Apache 2.0 下获得许可)

      基本上您只需将高度/宽度设置为等于另一个维度(取决于您要缩放的方式)

      注意:您可以使用 scaleType 属性在不使用自定义类的情况下将其设为正方形,但视图的边界会超出可见图像,如果您在其附近放置其他视图,则会出现问题。

      【讨论】:

        【解决方案8】:

        在 Android 26.0.0 PercentRelativeLayout has been deprecated.

        现在解决它的最佳方法是使用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>
        


        这是一个tutorial,介绍如何将ConstraintLayout 添加到您的项目中。

        【讨论】:

          【解决方案9】:

          要将 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();
          

          【讨论】:

            【解决方案10】:

            对于现在路过的人来说,在 2017 年,实现您想要的新的最佳方式是使用 ConstraintLayout,如下所示:

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

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

            Build a Responsive UI with ConstraintLayout

            此外,到目前为止,PercentRelativeLayout 已被弃用(请参阅Android documentation)。

            【讨论】:

              【解决方案11】:

              我是这样解决这个问题的:

              int pHeight =  picture.getHeight();
              int pWidth = picture.getWidth();
              int vWidth = preview.getWidth();
              preview.getLayoutParams().height = (int)(vWidth*((double)pHeight/pWidth));
              

              预览 - 宽度设置为“match_parent”且 scaleType 设置为“cropCenter”的 imageView

              picture - 要在 imageView src 中设置的位图对象。

              这对我来说效果很好。

              【讨论】:

              • 你还没有解释这个代码必须放在哪里。您也没有解释为什么要使用= vw*ph/pw 而不是更简单的= vw。 (我认为您这样做是为了保留源图像的纵横比,而不是强制进行方形预览。)
              【解决方案12】:

              我认为您无法在 XML 布局文件中执行此操作,而且我认为 android:scaleType 属性不会像您希望的那样工作。
              唯一的方法是以编程方式进行。您可以将宽度设置为fill_parent,可以将屏幕宽度作为View的高度,也可以使用View.getWidth()方法。

              【讨论】:

                【解决方案13】:

                ImageView 的“scaleType”功能在这里可以帮到你。

                此代码将保持纵横比并将图像置于顶部:

                android:layout_width="fill_parent"
                android:layout_height="fill_parent"
                android:scaleType="fitStart"
                

                这是一篇很棒的文章,展示了使用 scaleType 的可能性和外观。

                ImageView scaleType samples

                【讨论】:

                • "scaleType" 在这里没有帮助。目标是让 ImageView 本身始终是方形的,而不仅仅是其中的图像。使用 scaleType,ImageView 可能会比图片大。
                【解决方案14】:

                我确实喜欢这个 -

                layout.setMinimumHeight(layout.getWidth());
                

                【讨论】: