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

Android 如何将ImageView与底部对齐,填充其宽度和高度,并保持其纵横比? 背景,android,imageview,aspect-ratio,Android,Imageview,Aspect Ratio,ImageView有各种XML属性可用于缩放其内容,还有各种布局视图可用于放置视图和设置其大小 但是,在某些情况下,我不知道如何很好地缩放imageView 例如,将ImageView放在框架布局的底部,尽可能地缩放其宽度,并保持纵横比(不进行裁剪) 问题 我发现的组合都不起作用,包括各种ScaleType值、adjustViewBounds、gravity等等 ImageView似乎遗漏了一些重要的ScaleType值 我试过的 到目前为止,唯一对我有效的解决方案是将imageView设置为底

ImageView有各种XML属性可用于缩放其内容,还有各种布局视图可用于放置视图和设置其大小

但是,在某些情况下,我不知道如何很好地缩放imageView

例如,将ImageView放在框架布局的底部,尽可能地缩放其宽度,并保持纵横比(不进行裁剪)

问题 我发现的组合都不起作用,包括各种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);
这通常是可行的,当它不是全屏的时候,不需要太多的修改就可以工作,但我想知道是否有更简单的方法

如果高度太大,它可能不起作用,因此您可能需要更改它,以便在出现这种情况时,将宽度设置为更小,以使所有内容都适合容器

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


编辑:这是我试图做的一个示例图像,这次是在一个垂直的线性布局中,它限制了中间的IVIEVIEW,在2个其他视图之间:

如您所见,在部分(或全部?)预览中,中间图像向右对齐,而不是停留在中间(水平)

我想让它占据所有的空间和比例(保持纵横比),同时与它拥有的空间底部对齐

下面是我尝试过的一种组合的示例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>

再次请注意,我尝试了多种组合,但都不起作用,因此如果您建议在XML中进行一些更改,请先尝试一下。还要注意的是,上面是一个POC(为了便于阅读)

顺便说一句,我建议的解决方法适用于某些(或大多数?)情况,但不是所有情况。你只需旋转你的设备就可以注意到它。也许有办法修复它,或者从ImageView扩展以提供额外的保护壳。

我使用了android:scaleType=“fitXY”,但它让我尝试了很多次,直到图像适合整个屏幕的XY,,,我的意思是scaleType中有一个wierd bug,fitEnd可以正常工作,但是您需要删除它并重新写入,直到它适合任何屏幕的末尾,而不会出现错误。底线scaleType有很多bug,直到它提供了您所需要的东西为止。

尝试使用
android:scaleType=“fitCenter”

编辑


嗯,我明白你的意思了,另一个选择是让它在纵向xml上使用
fitEnd
,并使用
android:scaleType=“fitCenter”
在layout land文件夹上创建一个相同的xml(如果需要的话创建),该文件夹将仅用于横向视图

这是一个证明om概念的自定义图像视图,您需要添加缺少的构造函数并执行矩阵设置 每当ImageView的可绘制更改时:

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);
        }
    }
}
简而言之,它是如何工作的:

  • 首先,通过调用stf=
    Matrix.ScaleToFit.CENTER
    来设置矩阵,结果与
    ImageView.ScaleType.FIT\u CENTER

  • 然后,为了将可绘制对象与底部矩阵对齐,调用mapPoints(),它映射可绘制对象的左/下角,结果是在ImageView中看到的变换点

  • 最后,
    Matrix.postTranslate()
    将Y轴上的矩阵转换为ImageView的底部


您需要三个属性的组合:

android:layout_height="wrap_content"
android:scaleType="fitCenter"
android:adjustViewBounds="true"

需要使用
adjustViewBounds
属性,因为默认情况下,
ImageView
测量自身以匹配可绘图的原始尺寸,而不考虑根据缩放类型执行的任何缩放。

首先,从我阅读的布局来看,我不太明白你们到底想要什么来将图片对齐到底。我的布局将使图像居中,缩放您可以修改底部视图的高度,以查看图像的外观。更改顶视图或底视图的高度图像大小将根据imageView的可用空间进行放大或缩小

<?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:orientation="vertical">

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


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

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

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


希望这能解决您的问题。

您可以使用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);
        }

    }
}

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

ImageView.ScaleType.FIT\u END呢?@pskink我已经尝试过了。它会将图像缩放到其最右端。我试过:android:layout\u width=“match\u parent”android:layout\u height=“wrap\u content”android:layout\u gravity=“bottom”android:adjustViewBounds=“true”android:scaleType=“fitEnd”@pskink但是如果我将高度设置为“match\u parent”,我不确定看到了什么。这就是你的意思吗?然后贴一张你得到的图片,试试这个“fitXY”在你不关心纵横比的时候使用。关于“fitEnd”,它的行为方式很奇怪,所以我不确定这是否是最好的。是否有替代imageView的方法?也许是第三方图书馆?或者可能对scaleType使用矩阵?fitEnd是做你想做的事情的正确方法,你有什么问题吗?@pskink试试吧。我已经测试过了,但它在所有预览中都不能正常工作。效果不好。也试试看。对于一个preivew屏幕(例如Nexus 7),它看起来位于可用空间的中心。不,我希望它以相同的方式缩放所有屏幕。在ImageView下面不应该有任何空白,除非您使用非常宽的图像,否则景观上的fitCenter会使图像拉伸到fu