缩放ImageView以适应设备宽度

16

在我的Android应用程序中,我有一个显示以下大小的图像的活动:244 x 330。 我想在整个设备宽度上显示这些图像。

我的布局文件如下所示:

<?xml version="1.0" encoding="utf-8"?>
<ScrollView
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent">

    <LinearLayout 
      android:layout_width="fill_parent"
      android:layout_height="fill_parent"
      android:orientation="vertical">

            <ImageView android:id="@+id/news_image" 
                android:layout_height="fill_parent" 
                android:layout_width="fill_parent"
                android:layout_marginLeft="18dip"
                android:layout_marginRight="18dip"
                android:background="#aaaaaa" />


    </LinearLayout>

</ScrollView>

我试图设置ImageView的ScaleType,但是没有一个ScalingType可以使ImageView按比例缩放。如何按比例缩放图像以适应横向模式和纵向模式下的整个屏幕?
基本上我想要的是类似于ScaleType.CENTER_CROP,但也设置了图像的比例高度,这样我就可以看到所有的图像而不仅仅是部分图像。
编辑原因是我知道我的问题有点让你困惑。
我想用一张图片向您展示。这是我目前在布局中得到的。我想通过尽可能大地缩放图像来填充整个灰色区域。我该怎么做?

当我将ScaleType设置为CENTER_CROP时,我会得到这个结果。

但这并不是我想要的,因为你只能看到中心的一部分图像。

而我想要的是:

我希望这能帮助你理解我想要实现的内容。有人知道怎么做吗?
编辑2:
可能看起来有些奇怪和令人困惑,因为我试图显示一个比屏幕尺寸更高的图像,但由于在我的示例布局中使用了ScrollView,所以这应该没问题,用户可以滚动以查看未显示的区域。
希望这能帮助你理解我想要做的事情。
9个回答

30

我尝试了在ImageView中使用每一种ScaleType,包括fill_parentwrap_content,但它们都没有起作用。我也尝试了Google上找到的所有方法,但对我来说都没有用,于是我自己想出了一些方法。

很明显,ImageView没有按照我想要的方式对图像进行缩放,所以我必须自己对其进行缩放。在缩放位图后,我会将新的位图设置为ImageView的图像源。在G1和Motorola Milestone 2上,这个方法效果非常好,看起来也很好。

以下是我的全部代码:

布局:

<ScrollView
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent">

    <LinearLayout 
      android:layout_width="fill_parent"
      android:layout_height="fill_parent"
      android:id="@+id/news_wrapper">

            <ImageView android:id="@+id/news_image" 
                android:layout_height="fill_parent"
                android:layout_width="fill_parent"
                android:layout_marginLeft="18dip"
                android:layout_marginRight="18dip"
                android:background="#aaaaaa" />

    </LinearLayout>

</ScrollView>

活动

public class ScalingImages extends Activity {

    private ImageView imageView;

    /** Called when the activity is first created. */
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.test_margin);

        this.imageView = (ImageView)findViewById(R.id.news_image);

        // The image is coming from resource folder but it could also 
        // load from the internet or whatever
        Drawable drawable = getResources().getDrawable(R.drawable.img);
        Bitmap bitmap = ((BitmapDrawable)drawable).getBitmap();

        // Get scaling factor to fit the max possible width of the ImageView
        float scalingFactor = this.getBitmapScalingFactor(bitmap);

        // Create a new bitmap with the scaling factor
        Bitmap newBitmap = Util.ScaleBitmap(bitmap, scalingFactor);

        // Set the bitmap as the ImageView source
        this.imageView.setImageBitmap(newBitmap);
    }

    private float getBitmapScalingFactor(Bitmap bm) {
        // Get display width from device
        int displayWidth = getWindowManager().getDefaultDisplay().getWidth();

        // Get margin to use it for calculating to max width of the ImageView
        LinearLayout.LayoutParams layoutParams = 
            (LinearLayout.LayoutParams)this.imageView.getLayoutParams();
        int leftMargin = layoutParams.leftMargin;
        int rightMargin = layoutParams.rightMargin;

        // Calculate the max width of the imageView
        int imageViewWidth = displayWidth - (leftMargin + rightMargin);

        // Calculate scaling factor and return it
        return ( (float) imageViewWidth / (float) bm.getWidth() );
    }
}

工具类

public class Util {

    public static Bitmap ScaleBitmap(Bitmap bm, float scalingFactor) {
        int scaleHeight = (int) (bm.getHeight() * scalingFactor);
        int scaleWidth = (int) (bm.getWidth() * scalingFactor);

        return Bitmap.createScaledBitmap(bm, scaleWidth, scaleHeight, true);
    }

}
如果有更好或更准确的方法来实现相同的缩放,请告诉我,因为我不能相信这样一个微不足道的事情如此难以实现。我真的希望能看到更好的方法来完成这个任务。谢谢阅读。

2
感谢分享。应该有一个缩放因子来完成这个操作。 - binW
1
非常感谢 - 我无法相信没有更简单的方法来做到这一点! - John McCollum
1
我也浪费了很多时间尝试在xml中使用设置。感谢您发布自己的解决方案。 - ggenglish
1
getWidth() 现在已经被弃用,所以我改用这个方法... Point size = new Point(); getWindowManager().getDefaultDisplay().getSize(size); int displayWidth = size.x; - ban-geoengineering

20
最简单的方法是在ImageView中添加android:adjustViewBounds="true",并将比例类型设置为“fitCenter”。

简单的需求有简单的解决方案 - 对我来说很有效。(这应该是正确的答案!) - ban-geoengineering
这个解决方案非常完美。 - Pavan Bilagi

4
有点困惑您到底想要什么。如果您要缩放以适应屏幕,则有三个选项,其中两个选项在保持比例的情况下是可行的。您可以使用ScaleType fitCenter,这将使图像按比例适合边界,或者您可以使用centerCrop(您说您尝试过),这将拉伸图像的最短边以适应容器(这意味着某些内容将被裁剪掉在更长的维度上)。如果不进行裁剪或者不成比例地拉伸,就不能将其拉伸以适应宽度和高度。

编辑:好的,我现在明白您的意思了。首先,我会将您的LinearLayout的高度设置为wrap_content。其次,在代码中,以下是我能想到的一种方法。还可能有另一种方法,即首先获取屏幕尺寸,然后使用新尺寸进行createScaledBitmap,然后设置背景资源。

final ImageView newsImage = (ImageView)findViewById(R.id.news_image);

//get details on resolution from the display
DisplayMetrics metrics = new DisplayMetrics();
getWindowManager().getDefaultDisplay().getMetrics(metrics);

//going to set what happens as the layout happens
newsImage.getViewTreeObserver().addOnGlobalLayoutListener(
    new ViewTreeObserver.OnGlobalLayoutListener() {

        public void onGlobalLayout() {
            int oldHeight, oldWidth, newHeight, newWidth;

            //we want the new width to be as wide as the screen
            newWidth = metrics.widthPixels;

            oldHeight = newsImage.getDrawable().getIntrinsicHeight();
            oldWidth = newsImage.getDrawable().getIntrinsicWidth();

            //keeping the aspect ratio, the new height should be w1/h1 = w2/h2
            newHeight = Math.floor((oldHeight * newWidth) / oldWidth);
            LinearLayout.LayoutParams params = 
                (LinearLayout.LayoutParams)newsImage.getLayoutParams();
            params.height = newHeight;
            params.width = newWidth;
            newsImage.setLayoutParams(params);
            newsImage.setScaleType(ScaleType.CENTER);
            newsImage.invalidate();
            newsImage.getViewTreeObserver().removeGlobalOnLayoutListener(this);
        }
    }
}

我尝试过使用ScaleType.CENTER_CROP,但是它确实裁剪了高度。你能提供一个示例吗?我会再次尝试(也许我在某个地方犯了错误),并发布我的结果。 - OemerA
如果你想让它适合宽度,你必须缩减高度。要实现你想要的效果,可以使用fitXY缩放类型,但这会导致不成比例的缩放。没有其他方法可以做到这一点。 - Kevin Coppock
但我不想将图像适应屏幕的高度。如果图像比显示高度大,用户可以滚动图像,因为我在示例中使用了ScrollView。我想要的是适合宽度但不裁剪高度,并且如果高度大于显示高度,则可以滚动。有什么建议吗? - OemerA

4

我到处搜索,但找不到解决方案。以下是我为自己找到的可与滚动视图一起使用的方法:

XML文件:

<ScrollView xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:fillViewport="true" >

    <ImageView
        android:id="@+id/manga_page_image"
        android:layout_width="match_parent"
        android:layout_height="0dp"
        android:adjustViewBounds="true"
        android:scaleType="fitCenter" />
</ScrollView>

确认!这对我也起作用了,而且比通过代码缩放图像要容易得多。 - chip

2
我希望能够将这些图片以设备宽度的全屏形式展示。
这很简单。你只需要更改错误的边距设置即可。删除以下这些行,你的图片将以设备宽度的全屏形式展示:
android:layout_marginLeft="18dip"
android:layout_marginRight="18dip" 

这似乎很奇怪,但实际上我希望有这些边距,否则它会像“粘”在屏幕上一样。除非左右两侧的18 dip,否则我想使用整个屏幕尺寸。 - OemerA

2

你是否尝试通过ImageView.setScaleType()进行程序设置?

setAdjustViewBounds(false)也可能有帮助。

编辑:抱歉,我读错了问题。不过,setAdjustViewBounds()仍然可能有帮助。我从未使用过它。


我刚刚尝试了 setAdjustViewBounds,但并没有起作用。还有其他建议吗?也许我的修改可以使我的目标更容易理解。 - OemerA

1

成功实现了我想要的,希望这也是你的目标:

@Override
public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.pgviewer);

    ImageView PgContainer = (ImageView)findViewById(R.id.imageView1);

    String Page = String.valueOf(getIntent().getExtras().getInt("Page"));
    try {
        PgContainer.setImageBitmap(getBitmapFromAsset(Page));
    } catch (IOException e) {
        // TODO Auto-generated catch block
        e.printStackTrace();
    }

    PgContainer.setScaleType(ScaleType.FIT_CENTER);
    PgContainer.scrollTo(0, 0);
    PgContainer.setScrollBarStyle(0);
}

然后对位图进行缩放:

private Bitmap getBitmapFromAsset(String strName) throws IOException
{
    AssetManager assetManager = getAssets();
    InputStream istr = assetManager.open(strName+".png");
    Bitmap bitmap = BitmapFactory.decodeStream(istr);

    float screenWidth = getResources().getDisplayMetrics().widthPixels;
    int ih=bitmap.getHeight();
    int iw=bitmap.getWidth();
    float scalefactor = screenWidth/iw;
    //w = 480, h=~
    //int newh = bitmap.getHeight()/bitmap.getWidth();
    return android.graphics.Bitmap.createScaledBitmap(bitmap, (int)(iw*scalefactor), (int)(ih*scalefactor), true);
    //return bitmap;
}

1

我不再看到图片了,而且这个问题很旧,但以防其他人遇到同样的问题。获取float screenWidth = getResources().getDisplayMetrics().widthPixels并通过编程方式设置ImageView LayoutParamters来将图像缩放到screenWidth,这样会更好,只是一个想法!!


0

其中一种方法是在 XML 文件中将 android:adjustViewBounds="true" 设置为 ImageView,并将缩放类型设置为 "fitCenter"。这应该可以按预期工作。 你也可以通过设置 ImageView.adjustViewBounds(true) 和 ImageView.setScaleType(ScaleType.FIT_CENTER) 来以编程方式完成。


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