【问题标题】:How to align ImageView to the bottom, fill its width and height, and keep its aspect ratio?ImageView如何对齐底部,填充它的宽度和高度,并保持它的纵横比?
【发布时间】:2020-09-24 15:07:13
【问题描述】:

背景

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);

这通常可以工作,并且不需要太多更改即可使其在未全屏时工作,但我想知道是否有更简单的方法。

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

问题

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


编辑:这是我正在尝试做的示例图像,这一次,在一个垂直的 LinearLayout 中,它在中间的 ImageView 之间,在其他 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 扩展以提供额外的情况。

【问题讨论】:

  • ImageView.ScaleType.FIT_END 怎么样?
  • @pskink 我试过了。它会将图像缩放到自身的最右端。我试过: android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_gravity="bottom" android:adjustViewBounds="true" android:scaleType="fitEnd"
  • @pskink 但是,如果我将高度设置为“match_parent”,我不确定我看到了什么。是你的意思吗?
  • 然后张贴你得到的图片
  • 所以试试这个pastebin.com/CAkuJa9Y

标签: android imageview aspect-ratio


【解决方案1】:

你需要三个属性的组合:

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

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

【讨论】:

  • 这适用于任何尺寸和纵横比的图像,对吧?比 ImageView 的尺寸更小和更大,对吧?
  • @androiddeveloper:是的,应该。但较小的图像不会被放大。
  • 你的意思是他们不会?但这就是我要求的全部目的……尽可能地扩展它。另外,你怎么说它不起作用,而我在这个示例中所做的是使用应用程序的小图标?请解释一下。
  • @androiddeveloper:对不起,我的错。是的,它也会升级。
  • 你能看看吗?我现在无法尝试...还可以尝试各种纵横比。
【解决方案2】:

你可以使用自定义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);
        }

    }
}

通过手动绘制您想要的底部对齐图像。

【讨论】:

    【解决方案3】:

    这是一个证明 om-concept 的自定义 ImageView,您需要添加缺少的构造函数并执行 Matrix 设置 每当 ImageView 的 Drawable 发生变化时:

    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 调用Matrix.setRectToRect() 设置矩阵,结果与ImageView.ScaleType.FIT_CENTER 相同

    • 然后为了使 Drawable 与底部对齐 Matrix.mapPoints() 被调用,它映射 Drawable 的左/下角,结果是变换点,就像在 ImageView 中看到的那样

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

    【讨论】:

    • 谢谢你。我已经得到了一个很好的答案(“corsair992”),它说我可以使用“wrap_content”作为 height ,“adjustViewBounds”设置为 true,“scaleType”设置为“fitCenter”。但是,我会给你 +1 的所有努力。
    • 它怎么会把图片调整到ImageView的底部呢?这是不可能的......例如只尝试没有上下视图的 ImageView:图像将居中
    • 在我编写的示例中使用它。我把它放在一个 FrameLayout 里面(使用重力),因为 ImageView 只需要它需要的大小,所以它会在底部。现在我已经阅读了他所写的内容,也许他提供的最终情况不起作用?
    【解决方案4】:

    尝试使用 android:scaleType="fitCenter"

    编辑

    嗯,我明白你的意思了,另一种选择是在纵向 xml 上使用 fitEnd,并在 layout-land 文件夹上创建一个相同的 xml(如果需要,创建它),android:scaleType="fitCenter" 将用于横向只有

    【讨论】:

    • 效果不佳。也试试。对于其中一个 preivew 屏幕(例如 Nexus 7),它看起来位于可用空间的中心。
    • 不,我希望它在所有屏幕上都以相同的方式缩放。 ImageView 下面不应该有任何空白
    • 除非您使用极宽的图像,否则横向上的 fitCenter 将导致图像拉伸到全高,因此它的上方/下方不会有任何空白
    • 图像可以有不同的大小(当然,应用程序应该在所有屏幕上都能正常工作),所以这不是解决方案。对不起。
    • @androiddeveloper:你需要将fitCenter的比例类型与wrap_content的高度结合起来,并将adjustViewBounds设置为true
    【解决方案5】:

    我使用了 android:scaleType="fitXY" 但它让我尝试了很多次,直到图像确实适合整个屏幕的 XY,我的意思是 scaleType 中有一个奇怪的错误,fitEnd 会起作用很好,但您需要将其删除并再次写入,直到它适合任何屏幕的末尾而不会出现压缩。底线 scaleType 有错误和错误,直到它为您提供所需的内容。

    【讨论】:

    • "fitXY" 在您不关心纵横比时使用。关于“fitEnd”,它的行为方式很奇怪,所以我不确定这是否是最好的。是否有替代 imageView 的方法?也许是第三方图书馆?或者也许使用矩阵作为 scaleType ?
    • fitEnd 是做你想做的事的正确方法,你有什么样的问题?
    • @pskink 试试吧。我已经对其进行了测试,但对于所有预览,它总是无法正常工作。
    【解决方案6】:

    首先,从我阅读您的布局来看,我真的不明白您真正想要将图像与底部对齐的目的。我的布局将使图像居中,并缩放您可以修改底部视图的高度以查看图像的外观。更改顶部或底部视图的高度,图像大小将根据 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>
    

    希望这能解决您的问题。

    【讨论】:

    • 不明白为什么横向模式下图像不居中?它以横向模式在我的屏幕上居中。
    猜你喜欢
    • 1970-01-01
    • 2012-06-05
    • 2013-08-07
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-07-01
    • 2014-01-02
    • 1970-01-01
    相关资源
    最近更新 更多