Sabtu, 26 Mei 2012

Auto resize bitmap to fit View

Last article demonstrate Reduce bitmap by setting inSampleSize of BitmapFactory.Options manually. In this article we are going to calculate the most optimize inSampleSize value to fit within a area. In our case, the ImageView is place inside a LinearLayout with "fill_parent" on both layout_width and layout_height. We try to get the best inSampleSize to create bitmap most fit in the LinearLayout.

Auto resize to fit View


In order to calulate the resize ratio, we need the expected width and height of the parent LinearLayout. BUT we cannot direct get it in onCreate() call-back method. Because when onCreate() is called, the layout not yet drawn and both getWidth() and getHeight() return 0. In the code, I display the getWidth() and getHeight() in onCreate(), onStart() and onResume() for your reference. So...how can I know when the layout is drawn? it's android.view.ViewTreeObserver.

android.view.ViewTreeObserver is used to register listeners that can be notified of global changes in the view tree. Such global events include, but are not limited to, layout of the whole tree, beginning of the drawing pass, touch mode change.... A ViewTreeObserver should never be instantiated by applications as it is provided by the views hierarchy. Refer to getViewTreeObserver() for more information.


onGlobalLayout() of ViewTreeObserver.OnGlobalLayoutListener is Callback method to be invoked when the global layout state or the visibility of views within the view tree changes.

Such that we can register our OnGlobalLayoutListener to get parent LinearLayout width and height, to perform the auto-resize.

(I also tried to do it in onPreDraw() of ViewTreeObserver.onPreDrawListener. But it seem that to be called too many times!)

Please note that inSampleSize is int value, that means we cannot get a 100% fit value. That's why I place HorizontalScrollView and ScrollView outside the ImageView, you can still scroll it. If you want a visually full-fit ImageView, simple remove HorizontalScrollView and ScrollView.

package com.AndroidResizeBigPicture;

import android.app.Activity;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.os.Bundle;
import android.view.ViewTreeObserver;
import android.view.ViewTreeObserver.OnGlobalLayoutListener;
import android.view.ViewTreeObserver.OnPreDrawListener;
import android.widget.ImageView;
import android.widget.LinearLayout;
import android.widget.TextView;
import android.widget.Toast;

public class AndroidResizeBigPictureActivity extends Activity {


TextView resizeLevel;
ImageView imageView;
LinearLayout imageParent;

Bitmap bitmap_Source;

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

resizeLevel = (TextView)findViewById(R.id.resizelevel);
imageView = (ImageView)findViewById(R.id.imageview);
imageParent = (LinearLayout)findViewById(R.id.imageparent);

ToastInfo("onCreate");

ViewTreeObserver viewTreeObserver = imageParent.getViewTreeObserver();
viewTreeObserver.addOnGlobalLayoutListener(onGlobalLayoutListener);
//viewTreeObserver.addOnPreDrawListener(onPreDrawListener);
}

OnGlobalLayoutListener onGlobalLayoutListener
= new OnGlobalLayoutListener(){

@Override
public void onGlobalLayout() {
/*
* Callback method to be invoked when the global layout state
* or the visibility of views within the view tree changes
*/
ToastInfo("onGlobalLayout");
imageView.setImageBitmap(
resize(imageParent.getWidth(), imageParent.getHeight()));
}

};

OnPreDrawListener onPreDrawListener
= new OnPreDrawListener(){

@Override
public boolean onPreDraw() {
/*
* Callback method to be invoked when the view tree is about
* to be drawn. At this point, all views in the tree have been
* measured and given a frame. Clients can use this to adjust
* their scroll bounds or even to request a new layout before
* drawing occurs.
*/

ToastInfo("onPreDraw");
imageView.setImageBitmap(
resize(imageParent.getWidth(), imageParent.getHeight()));

return true;
}};

private void ToastInfo(String caller){
Toast.makeText(getBaseContext(),
caller + " - " +
imageParent.getWidth() + " : " + imageParent.getHeight(),
Toast.LENGTH_LONG).show();
}

@Override
protected void onStart() {
// TODO Auto-generated method stub
super.onStart();
ToastInfo("onStart");
}

@Override
protected void onResume() {
// TODO Auto-generated method stub
super.onResume();
ToastInfo("onResume");
}

private Bitmap resize(int width, int height){

BitmapFactory.Options bmpFactoryOptions = new BitmapFactory.Options();
bmpFactoryOptions.inJustDecodeBounds = true;
Bitmap bitmap = BitmapFactory.decodeResource(
getResources(), R.drawable.testpicture, bmpFactoryOptions);

int heightRatio = (int)Math.ceil(bmpFactoryOptions.outHeight/(float)height);
int widthRatio = (int)Math.ceil(bmpFactoryOptions.outWidth/(float)width);

if (heightRatio > 1 || widthRatio > 1)
{
if (heightRatio > widthRatio)
{
bmpFactoryOptions.inSampleSize = heightRatio;
resizeLevel.setText("inSampleSize= " + heightRatio);
} else {
bmpFactoryOptions.inSampleSize = widthRatio;
resizeLevel.setText("inSampleSize= " + widthRatio);
}
}else{
resizeLevel.setText("inSampleSize= N/A");
}

bmpFactoryOptions.inJustDecodeBounds = false;
bitmap = BitmapFactory.decodeResource(getResources(),
R.drawable.testpicture, bmpFactoryOptions);
return bitmap;
}

}


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

<TextView
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:text="@string/hello" />
<TextView
android:id="@+id/resizelevel"
android:layout_width="fill_parent"
android:layout_height="wrap_content" />
<LinearLayout
android:id="@+id/imageparent"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:orientation="vertical" >
<HorizontalScrollView
android:layout_width="wrap_content"
android:layout_height="wrap_content">
<ScrollView
android:layout_width="wrap_content"
android:layout_height="wrap_content">
<ImageView
android:id="@+id/imageview"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:scaleType="center" />
</ScrollView>
</HorizontalScrollView>
</LinearLayout>

</LinearLayout>


Notice: You have to place your testpicture.jpg in /res/drawable/ folder.


0 komentar:

Posting Komentar

Copyright © 2012 Codding News All Right Reserved