Scaling ImageView to device width

 ̄綄美尐妖づ 提交于 2019-11-27 18:37:04

I tried really every ScaleType in my ImageView with fill_parent and wrap_content but no of them worked. I also tried everything what I found on Google but nothing worked for me either so came up with something on my own.

It was clear that the ImageView is not scaling my image like I wanted to be scaled so I had to scale it on my own. After scaling the bitmap I would set the new Bitmap as the image source to the ImageView. This works pretty good and looks very good on the G1 and on the Motorola Milestone 2.

And here is all pieces of my code

Layout:

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

Activity

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

Util class

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

}

If there is an better or more accurate way to accomplish the same scaling please let me know because I can't believe that such a trivial thing is so hard to accomplish.

I'm really hoping to see a better way to do this.

Thank you for reading.

the easiest way is to add android:adjustViewBounds="true" to the ImageView and set the scale type to "fitCenter"

Slightly confused on what you're looking for, exactly. If you're scaling to fit the screen, you have three options, two of which are viable if you're keeping proportions. You can use ScaleType fitCenter, which will make the image fit within the bounds proportionally, or you can use centerCrop (which you said you tried), which will stretch the shortest side of the image to fit the container (meaning some will get cropped off on the longer dimension). You can't have it stretch to fit the width AND height without either cropping, or stretching disproportionately.

EDIT: Okay, I think I get your point now. First, I'd set your LinearLayout to wrap_content for the height. Second, in code, here's one way you can do it that I can think of. There's probably also another way you could do it by first getting the screen dimensions, and then doing createScaledBitmap with the new dimensions, and then setting the background resource.

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

I googled everywhere and could not find a solution. Here is what I did, that worked for me and with a scroll view.

XML file:

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

Have you tried setting it programmatically via ImageView.setScaleType()?

setAdjustViewBounds( false ) might help as well.

Edit: sorry, I mis-read the question. Regardless, setAdjustViewBounds() still might help. Never used it though.

I want to show those images in full device width.

This is simple. You just have the wrong margin settings. Remove these lines and your image will show in full device width:

android:layout_marginLeft="18dip"
android:layout_marginRight="18dip" 

I don't see the images anymore and the question is old but just in case someone else finds this and has the same problem. Wouldn't it be better to just get float screenWidth = getResources().getDisplayMetrics().widthPixels and set the ImageView LayoutParamters programmatically to scale the image to screenWidth. Just an idea !!

manage to achieve what I wanted, which hopefully is the same as your aim:

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

then to scale the bitmap:

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

One of the ways to do it is by setting android:adjustViewBounds="true" to the ImageView and set the scale type to "fitCenter" in the xml file. This should work as expected. You can also do this programatically by setting ImageView.adjustViewBounds(true) and ImageView.setScaleType(ScaleType.FIT_CENTER).

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!