安卓如何将ImageView拉伸以填满宽度、保持宽高比且顶部对齐?

3
我想扩展一个位于RelativeLayout内部的ImageView。我希望它的宽度填满父容器,同时保持图像的纵横比。这听起来很像我可以在XML布局文件中使用centerCrop。区别在于,我不想让图像居中对齐。我想要的是将图像与父容器顶部对齐,将图像底部多余的部分裁剪掉。
以下是XML代码:
<RelativeLayout
        android:background="#f00"
        android:id="@+id/skyline_header"
        android:layout_width="match_parent"
        android:layout_height="0dp"
        android:layout_weight="25">

        <ImageView
            android:id="@+id/bg_image"
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:src="@drawable/bg_img"/>
</RelativeLayout>

这是我的代码:

final RelativeLayout headerContainer = (RelativeLayout) view.findViewById(R.id.skyline_header);
final ImageView iv = (ImageView) view.findViewById(R.id.bg_image);

ViewTreeObserver vto = headerContainer.getViewTreeObserver();

vto.addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {

    @Override
    public void onGlobalLayout() {

        headerContainer.getViewTreeObserver().removeOnGlobalLayoutListener(this);

        double imgAspectRatio = (double)iv.getMeasuredWidth() / (double)iv.getMeasuredHeight();

        int screenWidth = getActivity().getResources().getDisplayMetrics().widthPixels;

        Log.d("tag", Integer.toString(iv.getMeasuredWidth()));
        Log.d("tag", Integer.toString(iv.getMeasuredHeight()));
        Log.d("tag", Double.toString(imgAspectRatio));
        Log.d("tag", Integer.toString(screenWidth));

        int newHeight = (int) ((double)screenWidth * imgAspectRatio);

        img.setLayoutParams(new RelativeLayout.Layout(screenWidth, newHeight));
        img.requestLayout();
    }
});

这段代码的结果与设置scaleType="fitCenter"完全相同。它填充了容器的高度,将图像居中,并在左右留有边距。
输出很奇怪。它显示图像视图的宽度与屏幕相同:

1440
562
2.5622775800711746
1440

希望这能在概念上传达我现在所拥有的东西。

enter image description here

我希望图片能够拉伸以填满整个水平空间(没有可见的红色留下),但不要让游泳者看起来异常宽大(即保持纵横比不变)。游泳者下方的水可以根据需要进行裁剪以满足前两个要求。

输出有什么奇怪的地方吗?ImageView 的 width 与父元素的 width 匹配 (android:layout_width=match_parent && 没有 padding),并且 scaleType 的默认值是 fitCenter,我不明白你想要做什么以及你确切的期望是什么。 - Farshad Tahmasbi
这里是我困惑的地方:图像的宽度(如绘制)大约是屏幕宽度的一半。我的日志输出旨在显示绘制时的确切尺寸,这显然与屏幕宽度不同。虽然scaleType的默认值是fitCenter,但我的代码旨在更改此图像的呈现方式,使其不再适合中心。正如我在帖子中所说,我的目标更接近于centerCrop,而不是居中对齐。 - AndroidDev
所以我宁愿不要被日志输出拖累,而是专注于为什么我的代码没有以我希望的方式重新绘制图像。 - AndroidDev
@Alex,与你的假设不同,ImageView 的宽度并不等于绘制部分的宽度。记录可绘制对象的尺寸,你会自己发现这一点。 - Farshad Tahmasbi
@ebyt - 那实际上是我尝试的第一件事。我希望宽度上使用简单的match_parent,高度上使用wrap_content就可以解决问题,但没有这样的运气。 - AndroidDev
显示剩余3条评论
1个回答

3

很幸运,Android API提供了另一个scaleTypematrix,所以你可以自由地展示想要的图片部分,将以下代码添加到ActivityonCreate方法中:

    final ImageView iv = (ImageView) findViewById(R.id.iv);
    iv.getViewTreeObserver().addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {
        @Override
        public void onGlobalLayout() {
            int viewWidth = iv.getMeasuredWidth();
            int viewHeight = iv.getMeasuredHeight();
            Drawable src = iv.getDrawable();
            if (src != null) {
                int srcWidth = src.getIntrinsicWidth();
                int srcHeight = src.getIntrinsicHeight();
                float wRatio = (float) viewWidth / srcWidth;
                float hRatio = (float) viewHeight / srcHeight;
                float scaleFactor = Math.max(wRatio, hRatio);
                float hTranslate = (viewWidth - scaleFactor * srcWidth) / 2;
                Matrix matrix = new Matrix();
                matrix.setScale(scaleFactor, scaleFactor);
                matrix.postTranslate(hTranslate, 0);
                iv.setScaleType(ImageView.ScaleType.MATRIX);
                iv.setImageMatrix(matrix);

                Log.i("test", "srcWidth: " + srcWidth);
                Log.i("test", "srcHeight: " + srcHeight);
                Log.i("test", "viewWidth: " + viewWidth);
                Log.i("test", "viewHeight: " + viewHeight);
                Log.i("test", "wRatio: " + wRatio);
                Log.i("test", "hRatio: " + hRatio);
                Log.i("test", "scaleFactor: " + scaleFactor);
                Log.i("test", "hTranslate: " + hTranslate);
            }
            iv.getViewTreeObserver().removeOnGlobalLayoutListener(this);
        }
    });

首先,您需要注册一个 OnGlobalLayoutListener,以便在正确的时间访问视图的尺寸(我相信您已经知道),然后使用提供的参数计算 wRatio(宽度比率)和 hRatio(高度比率),并选择较大的一个作为 scaleFactor(以确保 drawable 覆盖整个视图)。此外,您需要水平居中对齐 drawable(这就是 hTranslate 的作用),最后创建矩阵即可完成! 原始图像: enter image description here centerCrop 结果: enter image description here topCrop 结果(这是我们通过代码实现的): enter image description here

是的,我知道矩阵,但之前没有尝试将其作为解决这个问题的方法。非常感谢。这是一个很好的解决方案! - AndroidDev

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接