如何将ImageView对齐底部,填充其宽度和高度,并保持其纵横比?

and*_*per 12 android aspect-ratio imageview

背景

ImageView可以使用各种XML属性来扩展其内容,以及允许放置视图和设置其大小的各种布局视图.

但是,我无法弄清楚如何在某些情况下很好地缩放imageView.

它的一个例子是将ImageView放在底部(例如frameLayout),尽可能地缩放其宽度,并保持纵横比(不进行裁剪).

问题

我找不到任何组合,包括各种ScaleType值,adjustViewBounds,gravity,......

似乎ImageView错过了一些重要的ScaleType值.

我试过的

到目前为止,唯一对我有用的解决方案是将imageView设置为底部(使用重力设置为底部和中心水平),并使用代码,类似于:

final ImageView logoBackgroundImageView = ...;
final LayoutParams layoutParams = logoBackgroundImageView.getLayoutParams();
final Options bitmapOptions = ImageService.getBitmapOptions(getResources(), R.drawable.splash_logo);
final int screenWidth = getResources().getDisplayMetrics().widthPixels;
layoutParams.height = bitmapOptions.outHeight * screenWidth / bitmapOptions.outWidth;
logoBackgroundImageView.setLayoutParams(layoutParams);
Run Code Online (Sandbox Code Playgroud)

这通常是有效的,并且不需要做太多改动就可以使它在不是全屏时工作,但我想知道是否有更简单的方法.

如果高度太大,它可能无法工作,因此您可能想要更改它,以便在发生这种情况时,将宽度设置为较小以允许所有内容都适合容器.

这个问题

是否有解决方案或库来修复与ImageView相关的各种问题?


编辑:这是我正在尝试做的一个示例图像,这次,在一个垂直的LinearLayout中,在中间的ImageView中,在另外两个视图之间:

在此输入图像描述

正如您所看到的,在某些(或所有?)预览中,中间图像与右侧对齐,而不是停留在中间(水平).

我想让它占用它所有的空间并缩放(保持纵横比),然后与它所拥有的空间的底部对齐.

这是我试过的一个组合的XML示例:

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
                android:layout_width="match_parent"
                android:layout_height="match_parent"
                android:background="#FF339AE2">

    <View
        android:layout_width="match_parent"
        android:id="@+id/topView"
        android:layout_alignParentTop="true"
        android:layout_height="100dp"
        android:background="#FF00ff00"
        />


    <FrameLayout
        android:layout_below="@+id/topView"
        android:layout_width="match_parent"
        android:layout_centerHorizontal="true"
        android:layout_above="@+id/bottomView"
        android:layout_height="match_parent">

        <ImageView
            android:layout_width="match_parent"
            android:background="#FFffff00"
            android:layout_gravity="bottom|center_horizontal"
            android:src="@android:drawable/sym_def_app_icon"
            android:scaleType="fitEnd"
            android:layout_height="match_parent"
            />
    </FrameLayout>

    <View
        android:background="#FFff0000"
        android:layout_alignParentBottom="true"
        android:layout_centerHorizontal="true"
        android:id="@+id/bottomView"
        android:layout_width="match_parent"
        android:layout_height="100dp"/>

</RelativeLayout>
Run Code Online (Sandbox Code Playgroud)

再次注意,我已经尝试了多种组合,但它们都没有工作,因此如果您建议在XML中进行更改,请先尝试一下.另请注意,以上是POC(以便于阅读).

顺便说一句,我建议的解决方法适用于某些(或大多数?)案例,​​但不是全部.只需旋转设备即可注意到它.也许有办法解决它,或从ImageView扩展以提供额外的案例.

cor*_*992 26

您需要三个属性的组合:

android:layout_height="wrap_content"
android:scaleType="fitCenter"
android:adjustViewBounds="true"
Run Code Online (Sandbox Code Playgroud)

adjustViewBounds属性是必需的,因为ImageView默认情况下测量自身以匹配可绘制的原始尺寸,而不考虑根据比例类型执行的任何缩放.


Joh*_*nny 8

您可以使用is custom FitWidthAtBottomImageView来实现此代码:

public class FitWidthAtBottomImageView extends ImageView {
    public FitWidthAtBottomImageView(Context context) {
        super(context);
    }

    public FitWidthAtBottomImageView(Context context, AttributeSet attrs) {
        super(context, attrs);
    }

    public FitWidthAtBottomImageView(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
    }

    public FitWidthAtBottomImageView(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
        super(context, attrs, defStyleAttr, defStyleRes);
    }

    @Override
    protected void onDraw(Canvas canvas) {
        int i = getWidth() - getPaddingLeft() - getPaddingRight();
        int j = getHeight() - getPaddingTop() - getPaddingBottom();
        if (getBackground() != null) {
            getBackground().draw(canvas);
        }
        if (getDrawable() != null && getDrawable() instanceof BitmapDrawable) {
            Bitmap bitmap = ((BitmapDrawable) getDrawable()).getBitmap();
            int h = bitmap.getHeight() * i / bitmap.getWidth();
            canvas.drawBitmap(bitmap, null, new RectF(getPaddingLeft(), getPaddingTop() + j - h, getPaddingLeft() + i, getHeight() - getPaddingBottom()), null);
        } else {
            super.onDraw(canvas);
        }

    }
}
Run Code Online (Sandbox Code Playgroud)

通过手动绘制所需的底部对齐图像.


psk*_*ink 5

这是一个概念验证的自定义 ImageView,只要 ImageView 的 Drawable 发生更改,您就需要添加缺少的构造函数并执行 Matrix 设置:

class V extends ImageView {
    public V(Context context) {
        super(context);
        setScaleType(ScaleType.MATRIX);
    }
    @Override
    protected void onSizeChanged(int w, int h, int oldw, int oldh) {
        super.onSizeChanged(w, h, oldw, oldh);
        Drawable d = getDrawable();
        if (d != null) {
            Matrix matrix = new Matrix();
            RectF src = new RectF(0, 0, d.getIntrinsicWidth(), d.getIntrinsicHeight());
            RectF dst = new RectF(0, 0, w, h);
            matrix.setRectToRect(src, dst, Matrix.ScaleToFit.CENTER);
            float[] points = {
                    0, d.getIntrinsicHeight()
            };
            matrix.mapPoints(points);
            matrix.postTranslate(0, h - points[1]);
            setImageMatrix(matrix);
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

简而言之,它是如何工作的:

  • Matrix.setRectToRect()首先通过调用stf ==设置矩阵Matrix.ScaleToFit.CENTER,结果与ImageView.ScaleType.FIT_CENTER

  • 然后为了将 Drawable 与底部对齐 Matrix.mapPoints(),它会映射 Drawable 的左/下角,结果是变换后的点,如 ImageView 中所示

  • 最后Matrix.postTranslate()将 Y 轴上的 MAtrix 平移到 ImageView 的底部