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

时间:2013-12-02 09:55:39

标签: android imageview aspect-ratio

背景

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个视图之间:

enter image description here

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

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

这是我尝试过的一个组合的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扩展以提供额外的案例。

6 个答案:

答案 0 :(得分:24)

您需要三个属性的组合:

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

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

答案 1 :(得分:7)

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

    }
}

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

答案 2 :(得分:1)

这是一个自定义概念的自定义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.setRectToRect()调用Matrix.ScaleToFit.CENTER来设置矩阵,结果与ImageView.ScaleType.FIT_CENTER相同

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

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

答案 3 :(得分:0)

尝试使用 android:scaleType="fitCenter"

修改

嗯,我看到了你的意思,另一种选择是在肖像xml上设置fitEnd并在layout-land文件夹上创建一个相同的xml(如果需要,可以创建它)android:scaleType="fitCenter"仅用于景观

答案 4 :(得分:-1)

我使用了android:scaleType =“fitXY”,但它让我尝试了很多次,直到图像确实适合整个屏幕的XY ,,,我的意思是scaleType中有一个奇怪的错误,fitEnd会起作用很好但你需要删除它并再次写入,直到它适合任何屏幕的结束而不进行核对。底线scaleType有bug和bug,直到它为你提供所需的东西。

答案 5 :(得分:-1)

所有的拳头,我真的不明白你真正想要的是将图像与我阅读你的版面的底部对齐。我的布局将使图像居中,缩放您可以修改底部视图的高点以查看图像的外观。更改顶部或底部视图的高点,图像大小将向上或向下缩放,具体取决于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>

希望这能解决您的问题。