【问题标题】:Android XML - Have an ImageView fill height while maintaining ANY width ratioAndroid XML - 有一个 ImageView 填充高度,同时保持任何宽度比
【发布时间】:2016-11-09 05:16:21
【问题描述】:

我正在构建一个 Android 应用程序,现在正在设计用户配置文件活动。

它应该在一个看起来像横幅的矩形容器的顶部显示个人资料图片。

<ImageView
android:id="@+id/user_pic"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:scaleType="fitCenter"
android:adjustViewBounds="true"
android:background="@android:color/transparent"
android:layout_centerHorizontal="true"
android:elevation="2dp"/>

如果图像是 1x1 比例或高度大于宽度,则此 XML 代码运行良好。 (我在背景中显示了同一图像的模糊和拉伸版本,因此它并不完全丑陋)。

我遇到的问题WIDTH大于HEIGHT。它尝试缩放高度(在我的情况下为 300dp),但随后宽度到达布局的边界并停止调整大小,在图像下方留下空白空间。

知道 scaleType="centerCrop" 几乎可以满足我的要求,但是如果图像的比例是 1x1,它会被裁剪人的图像的顶部(大部分时间是头发),我不想要。

所以基本上,有没有办法在 XML 或 JAVA 中调整图像的高度以填充我的容器,同时保持宽度比并忽略父布局的最大宽度? (我想它应该像“centerCrop”一样裁剪溢出的内容)。

这是我目前正在实现的目标和正在发生的问题的图像。灰色部分是同一张Image的模糊和调整大小的版本,所以当图片无法填满宽度时(例如在1x1比例的图片中)看起来不会太难看。 https://i.stack.imgur.com/FUDcP.png

【问题讨论】:

  • 如有必要,我希望将宽度裁剪一点,以确保高度始终与容器的高度匹配,但我很确定它不能仅在 XML 中完成,因为似乎只有 centerCrop给我这个功能。 CenterCropWidth 将是一个惊人的 scaleType !
  • developer.android.com/reference/android/widget/… 此链接中提到了 8 种比例类型,尝试所有,如果没有工作,那么您必须以编程方式裁剪图像并设置为 ImageView

标签: android xml imageview


【解决方案1】:

我没有正确理解你,但你想保持图像的纵横比,你应该 match_parentandroid:height 并尝试 wrap_content ImageView 的宽度。尝试将fitCenter 设为android:scaleType

试试下面的代码 -

<ImageView
        android:id="@+id/user_pic"
        android:layout_width="wrap_content"
        android:layout_height="match_parent"
        android:scaleType="fitCenter"
        android:adjustViewBounds="true"
        android:background="@android:color/transparent"/>

【讨论】:

  • 是的,这基本上是我可以在纯 XML 中完成的最好的,但是如果您的图像具有较大的宽度和较小的高度,则会出现此解决方案的问题。它将尝试匹配父级的高度,但一旦图像的宽度达到父级布局的左右边界,它将无法匹配。如果您查看我在原始帖子中发布的图像,这几乎就是它给出的结果。
  • 然后您应该创建一个自定义视图并使用 ImageView 进行扩展,并根据您的需要更改 onMeasure 方法。也请尝试将 android:layout_width 设置为“wrap_content”。
【解决方案2】:

this link找到答案。

基本上,使用的技巧是在 Java 中创建一个自定义 ImageView 类,然后使用它。如有必要,它将根据情况计算正确的裁剪区域。

如果有人找到纯 XML 解决方案,请随时告诉我!

不用再等待,这是我使用的代码。

JAVA 类

public class FitYCropXImageView extends ImageView {
    boolean done = false;

    @SuppressWarnings("UnusedDeclaration")
    public FitYCropXImageView(Context context) {
        super(context);
        setScaleType(ScaleType.MATRIX);
    }

    @SuppressWarnings("UnusedDeclaration")
    public FitYCropXImageView(Context context, AttributeSet attrs) {
        super(context, attrs);
        setScaleType(ScaleType.MATRIX);
    }

    @SuppressWarnings("UnusedDeclaration")
    public FitYCropXImageView(Context context, AttributeSet attrs, int defStyle) {
        super(context, attrs, defStyle);
        setScaleType(ScaleType.MATRIX);
    }

    private final RectF drawableRect = new RectF(0, 0, 0,0);
    private final RectF viewRect = new RectF(0, 0, 0,0);
    private final Matrix m = new Matrix();
    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        super.onMeasure(widthMeasureSpec, heightMeasureSpec);
        if (done) {
            return;//Already fixed drawable scale
        }
        final Drawable d = getDrawable();
        if (d == null) {
            return;//No drawable to correct for
        }
        int viewHeight = getMeasuredHeight();
        int viewWidth = getMeasuredWidth();
        int drawableWidth = d.getIntrinsicWidth();
        int drawableHeight = d.getIntrinsicHeight();
        drawableRect.set(0, 0, drawableWidth, drawableHeight);//Represents the original image
        //Compute the left and right bounds for the scaled image
        float viewHalfWidth = viewWidth / 2;
        float scale = (float) viewHeight / (float) drawableHeight;
        float scaledWidth = drawableWidth * scale;
        float scaledHalfWidth = scaledWidth / 2;
        viewRect.set(viewHalfWidth - scaledHalfWidth, 0, viewHalfWidth + scaledHalfWidth, viewHeight);

        m.setRectToRect(drawableRect, viewRect, Matrix.ScaleToFit.CENTER /* This constant doesn't matter? */);
        setImageMatrix(m);

        done = true;

        requestLayout();
    }
}

XML

<com.app.YourAppName.YourAppName.CustomViews.FitYCropXImageView
                        android:id="@+id/user_pic"
                        android:layout_width="match_parent"
                        android:layout_height="match_parent"
                        android:background="@android:color/transparent"
                        android:elevation="2dp"
                        />

必要时的 JAVA 活动

import com.app.YourAppName.YourAppName.CustomViews.FitYCropXImageView;

FitYCropXImageView profilePic = (FitYCropXImageView) findViewById(R.id.user_pic);

【讨论】:

    【解决方案3】:

    如果您的 ImageView 宽度为 match_parent 并且您的原始图像大小为 300x400

    并假设 Deice 的 WIDTH_PIXEL 1080 和 HEIGHT_PIXEL 1920

    您的 ImageView 需要为 1080x1440(3:4)

    你可以像下面这样使用。

    public static final int WIDTH_PIXEL = Resources.getSystem().getDisplayMetrics().widthPixels;
    public static final int HEIGHT_PIXEL = Resources.getSystem().getDisplayMetrics().heightPixels;
    
    //ratioX : ratioY = givenX : X
    public static int getRatio(int ratioX, int ratioY, int givenX) {
        int result = (int) ((((float) ratioY * (float) givenX) / (float) ratioX) + 0.5f);
        //Log.v(TAG, "Request -> " + ratioX + " : " + ratioY + " = " + givenX + " : " + result);
        return result;
    }
    
    
    {//Usage
       int width = 300;
       int height = 400;
    
       int resultHeight = getRatio(width, height , WIDTH_PIXEL);
       myImageVIew.getLayoutParams().height = resultHeight ;
    }
    
    
    <ImageView  
        android:layout_width="match_parent"
        android:layout_height="wrap_content"/>    
    

    希望能给你一些启示。

    【讨论】:

      猜你喜欢
      • 2012-06-05
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2016-01-17
      • 2013-08-07
      相关资源
      最近更新 更多