Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why do I need to wrap an ImageView into a FrameLayout?

Here is a simple layout:

      <RelativeLayout             android:layout_width="match_parent"             android:layout_height="wrap_content">              <ImageView                 android:id="@+id/companyIcon"                 android:layout_width="wrap_content"                 android:layout_height="40dp" <!-- notice I've limited a height -->                 android:scaleType="fitStart"                 android:adjustViewBounds="true"                 android:layout_alignParentLeft="true" />              <TextView                 android:id="@+id/companyName"                 android:layout_width="wrap_content"                 android:layout_height="wrap_content"                 android:layout_toRightOf="@id/companyIcon"                 android:layout_marginLeft="3dp"                 android:layout_centerVertical="true"                 android:textStyle="bold"                 android:textColor="#20526d" />         </RelativeLayout> 

The height of an image I will set by setImageBitmap() is more that 40dp. Using this layout I have an extra space between ImageView and TextView, where did it come from? enter image description here

But after I wrap the ImageView with FrameLayout I don't have this unnecessary extra space:

<RelativeLayout             android:layout_width="match_parent"             android:layout_height="wrap_content">              <FrameLayout                 android:id="@+id/image_container"                 android:layout_width="wrap_content"                 android:layout_height="wrap_content">                  <ImageView                     android:id="@+id/companyIcon"                     android:layout_width="wrap_content"                     android:layout_height="40dp"                     android:scaleType="fitStart"                     android:adjustViewBounds="true"                     android:layout_alignParentLeft="true" />             </FrameLayout>              <TextView                 android:id="@+id/companyName"                 android:layout_width="wrap_content"                 android:layout_height="wrap_content"                 android:layout_toRightOf="@id/image_container"                 android:layout_marginLeft="3dp"                 android:layout_centerVertical="true"                 android:textStyle="bold"                 android:textColor="#20526d" />         </RelativeLayout> 

And the result:

enter image description here

Can you guys explain why shall I put ImageView into FrameLayout to have things as intended? Thank you very much.

like image 318
Eugene Avatar asked Jan 30 '13 16:01

Eugene


People also ask

What's the purpose of FrameLayout?

FrameLayout is designed to block out an area on the screen to display a single item. Generally, FrameLayout should be used to hold a single child view, because it can be difficult to organize child views in a way that's scalable to different screen sizes without the children overlapping each other.

What is the purpose of the ImageView?

Displays image resources, for example Bitmap or Drawable resources. ImageView is also commonly used to apply tints to an image and handle image scaling. To learn more about Drawables, see: Drawable Resources.

What is the difference between fragment and FrameLayout?

Show activity on this post. A framelayout, Relative View and a few others represents a view in android and is extended from viewgroup. A Fragment is a an an Object that is used to represent a portion of a user interface and is usually hosted in an activity. A fragment has a viewgroup which you can assign an XML layout.


2 Answers

The height of an image I will set by setImageBitmap() is more that 40dp. Using this layout I have an extra space between ImageView and TextView, where did it come from?

Since the android:layout_height="40dp" with a android:scaleType="fitStart", the image is getting scaled down (and to the left/start) to fit the height, so this "extra space" is actually the original width of the image, since your android:layout_width="wrap_content". I recreated your layout with my own image that is larger than 40dp. When you select the ImageView, you can see that its bounds stretch to the image's original width.

Original Layout

To further prove this, if I set android:scaleType="center", no fit is applied and you can see the ImageView's original width.

Original Layout not scaled to fit

Can you guys explain why shall I put ImageView into FrameLayout to have things as intended?

It appears that since your FrameLayout uses android:layout_width="wrap_content", it gets the correct scaled down width from your ImageView after it gets scaled due to android:adjustViewBounds="true". It is strange that the ImageView itself uses android:layout_width="wrap_content", but shows the original image's width, and not the scaled width. My hunch is that the height and width of ImageViews get set before the scaling is applied, so the ImageView gets the original image's width, but the parent FrameLayout gets the scaled width of it's ImageView child after the scaling is applied. This may not be true, but it appears that way to me.

However, you can solve the unscaled width issue (without using a FrameLayout) by using android:maxHeight="40dp" on the ImageView. You can then set android:layout_height="wrap_content" so your images can be smaller than 40dp if the image is smaller.

<ImageView     android:id="@+id/companyIcon"     android:layout_width="wrap_content"     android:layout_height="wrap_content"     android:layout_alignParentLeft="true"     android:adjustViewBounds="true"     android:maxHeight="40dp"     android:scaleType="fitStart" /> 

Original Layout using maxHeight

like image 56
Steven Byle Avatar answered Sep 24 '22 18:09

Steven Byle


This applies to almost all the view but answer is written considering specifically ImageView

Guideline to set Height and Width

Choose one of this three options only.

  1. Set both height and width to "WRAP_CONTENT"
  2. Set both height and width to "FILL_PARENT"
  3. Set both height and width to "FIXED SIZE"

    *Avoid using mixture of them say Width=WRAP_CONTENT and Height=FILL_PARENT

Guideline to set SCALETYPE for ImageView

What does ScaleType do?

It scale the image you set to the ImageView, It doesn't scale ImageView so when you set it to fitStart it will scale your image and show on the right but your imageView will remain same in terms of height and width as what you have specified.

As if you are using WRAP_CONTENT for height and width you don't need to specify ScaleType cause your ImageView is automatically going to be as big as your image.

As if you are using FILL_PARENT for height and width you will have option to show the image in Center,Start,End or in Full view.. so based on that you can choose your ScaleType.

As if you are using FIXED_SIZE fpr height and width you should opt for scaletype=FITXY.


Guideline to set Image into ImageView

As if you are setting image statically in XML then you have one image on your hand so you can create image of the size you wish as per your layout design and just move on with WRAP_CONTENT.

As if you are setting image at runtime after downloading it from somewhere, that time download the image and create bitmap of the size you prefer and then set it to ImageView


Specific to your case

You can see that your image is quite stretched and the text is not readable that's because you have downloaded and set image as it is but in smaller height and width.. rather you should have done like,

Set ImageView height and width to WRAP_CONTENT in XML file

                    <ImageView                     android:id="@+id/companyIcon"                     android:layout_width="wrap_content"                     android:layout_height="wrap_content"                     android:layout_alignParentLeft="true" /> 

Download image in your required size say 50X100, for example see this code

class LoadPics extends AsyncTask<Void, Bitmap, Bitmap> {     String urlStr;     ImageView iv;     int width, height;      public LoadPics(ImageView iv, String url, int width, int height) {         this.iv = iv;         this.urlStr = url;         this.width = width;         this.height = height;     }      @Override     protected Bitmap doInBackground(Void... params) {         try {                 InputStream in = null;                 try {                     URL url = new URL(urlStr);                     URLConnection urlConn = url.openConnection();                     HttpURLConnection httpConn = (HttpURLConnection) urlConn;                     httpConn.connect();                     in = httpConn.getInputStream();                 } catch (MalformedURLException e) {                     e.printStackTrace();                 } catch (IOException e) {                     e.printStackTrace();                 }                  BitmapFactory.Options o = new BitmapFactory.Options();                 o.inJustDecodeBounds = true;                  int scale = 2;                 if (o.outHeight > width || o.outWidth > height) {                     scale = 2 ^ (int) Math.ceil(Math.log(width                             / (double) Math.max(o.outHeight, o.outWidth))                             / Math.log(0.5));                 }                  if (scale <= 1 && o.outHeight > 150) {                     scale = 5;                 }                  BitmapFactory.Options o2 = new BitmapFactory.Options();                 o2.inSampleSize = scale;                 Bitmap b1 = BitmapFactory.decodeStream(in, null, o2);                 b1 = Bitmap.createScaledBitmap(b1, width, height, true);                 loader.addToCache(urlStr, b1);                 publishProgress(b1);          } catch (Exception e) {             e.printStackTrace();         }         return null;     }      @Override     protected void onProgressUpdate(Bitmap... values) {         super.onProgressUpdate(values);         iv.setImageBitmap(values[0]);     } } 

And call this method with your arguments,

new LoadPics(ivUser,imgURL,100,50).execute(); 
like image 28
MKJParekh Avatar answered Sep 22 '22 18:09

MKJParekh