Background
Suppose I want to show an image of the something using an ImageView, and I want to put new views on top of it (animated ImageViews that show pins on a world map image, for example, or a Switch view on top of a smartphone image).
This means that no matter how the ImageView shows the image, the views should be in it, inside correct spot, with the same size as specified, or in a size related to the imageView itself
The problem
As opposed to other views, the ImageView can have a certain size, but its content is something else (to keep aspect ratio).
What I tried
I tried to use ConstraintLayout, but this can't really help, because the ImageView can change its size (for example when changing orientation), and thus ruining the position I've given the views compared to the ImageView.
I've found some libraries that can handle a similar thing (like here) and I even asked a similar question before (here), but all those solutions are for a static image within the ImageView, yet what I search for is adding a view on top of an ImageView.
The question
How do I put the views on top of the ImageView's content correctly?
How do I also scale the views down/up compared to the size of the ImageView's content ?
Can ConstraintLayout be used to change the scale of the views according to the ImageView's size ?
Make FrameLayout with wrap_content around ImageView. Then you could set SwitchView on top of ImageView. You could align it to center, side or corners and using margins to get some fine position.
It still won't scale with image, but you can get pretty good results. If that doesn't fit you, you can programatically get width/height of ImageView and alter position (or margins) of SwitchView accordingly.
With below you can manage width of switch or any other view as per image view width
android:layout_alignLeft="#+id/imageView"
android:layout_alignRight="#+id/imageView"
<Switch
android:id="#+id/swi"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignLeft="#+id/imageView"
android:layout_alignRight="#+id/imageView" />
<ImageView
android:id="#+id/imageView"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_below="#+id/swi"
android:src="#drawable/download" />
In Java,
ImageView imgView = (ImageView) findViewById(R.id.imageView);
imageView.setBackgroundResource(R.drawable.yourDrawable);
int width = imgView.getDrawable().getIntrinsicWidth();
Switch switchKey = (Switch) findViewById(R.id.switchKey);
switchKey.setMinimumWidth(width);
And in XML, align it with alignLeft and alignRight with ImageView.
As far as i get it, you need the image size displayed inside the image view and set that as the max width of your switch view right?
You need both Java and XML for this,
The XML file is basically as RelativeLayout with the view stacked as needed.
<RelativeLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content">
<ImageView
android:src="#drawable/nonet_icon"
android:id="#+id/iconView"
android:layout_width="wrap_content"
android:layout_height="wrap_content" />
<android.support.v7.widget.SwitchCompat
android:layout_width="wrap_content"
android:visibility="gone"
android:layout_centerInParent="true"
android:layout_height="wrap_content"
android:id="#+id/switchView"/>
</RelativeLayout>
And the Java Code gets the imageWidth and sets it to the SwitchView.
mSwitchCompat.setVisibility(View.VISIBLE);
// 20% x 25% of Content in ImageView
final float x = mImageView.getDrawable().getIntrinsicWidth()*.2f;
final float y = mImageView.getDrawable().getIntrinsicHeight()*.25f;
// waiting for the view to be drawn
mSwitchCompat.post(new Runnable() {
#Override
public void run() {
// scale current view W.r.t. x and y values
mSwitchCompat.setScaleX((float)mSwitchCompat.getWidth()/x);
mSwitchCompat.setScaleY((float)mSwitchCompat.getHeight()/y);
}
});
RelativeLayout.LayoutParams layoutParams = new RelativeLayout.LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT,
WindowManager.LayoutParams.WRAP_CONTENT);
// 30% x 35% of content, for location
int xMargin = Math.round(mImageView.getDrawable().getIntrinsicWidth()*.3f);
int yMargin = Math.round(mImageView.getDrawable().getIntrinsicHeight()*.35f);
// set margin values, can optionally add for top and bottom
layoutParams.setMargins(xMargin,0,yMargin,0);
mSwitchCompat.setLayoutParams(layoutParams);
Ref: Getting Displayed image size of an ImageView
Trying to get the display size of an image in an ImageView
Ref: Dynamic size values
Do comment if you need a detailed explaination.
Example: Check this image!
Scaled View on Image: Scaled View on Image!
You can use MarginLayoutParams with Relative Layout to set left and top position in ImageView.
image = (ImageView) findViewById(R.id.imageID);
MarginLayoutParams marginParams = new MarginLayoutParams(image.getLayoutParams());
marginParams.setMargins(left_margin, top_margin, right_margin, bottom_margin);
RelativeLayout.LayoutParams layoutParams = new RelativeLayout.LayoutParams(marginParams);
image.setLayoutParams(layoutParams);
find complete information for this in below link :
MarginLayoutParams
Try this, may be it will help you.
<RelativeLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content">
<ImageView
android:id="#+id/img_background"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:scaleType="centerCrop"/>
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="#color/semi_transparent"
android:layout_margin="#dimen/spacing_small"
android:layout_alignTop="#+id/img_background"
android:layout_alignBottom="#id/img_background">
//this layout will expand according to your image size
</RelativeLayout>
</RelativeLayout>
Do you want to show switch that lay on imageview ?
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:id="#+id/ll_download"
android:layout_width="100dp"
android:layout_height="60dp"
android:layout_centerInParent="true"
android:orientation="vertical">
<ImageView
android:src="#android:drawable/btn_star_big_on"
android:layout_width="match_parent"
android:layout_height="match_parent" />
<Switch
android:id="#+id/mySwitch"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:text="Switch" />
</RelativeLayout>
First let's introduce me, I'm new in Android and mobile device programming, I previously worked on embedded systems running on QNX.
I hope I will respect the rules of this forum which seem to be quite stricts ;-).
I'm wrinting an application where I declare a layout for a welcome screen populated, between other things with a image view.
There is a first image placed in this image view in the xml file, but I will replace it by an other one later in the application's code and this second image will be potentially of a different size.
My problem is to resize and center my second image. According to my tests, it's quite automatic by using resources in Lint but it seems not so obvious by program, even if I read in the docs that it should be similar.
After reading several posts on the subject, I finally have a doubt; Can I center an image in an ImageView, or do I have to center the ImageView in the available space?
I tried the first solution without success.
So my layout is:
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:id="#+id/fragmentInit"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:paddingBottom="#dimen/activity_vertical_margin"
android:paddingLeft="#dimen/activity_horizontal_margin"
android:paddingRight="#dimen/activity_horizontal_margin"
android:paddingTop="#dimen/activity_vertical_margin"
tools:context="com.cabbonline.ndguidelt.MainActivity" >
<TextView
android:id="#+id/textViewAppName"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_above="#+id/textViewAppVersion"
android:layout_centerHorizontal="true"
android:text="#string/app_name" />
<TextView
android:id="#+id/textViewAppVersion"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_above="#+id/TextViewDevelopCabb"
android:layout_centerHorizontal="true"
android:text="#string/app_version" />
<TextView
android:id="#+id/TextViewDevelopCabb"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_above="#+id/imagecaBB"
android:layout_centerHorizontal="true"
android:text="#string/develop_cabb" />
<ImageView
android:id="#+id/imagecaBB"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_above="#+id/textViewCabbUrl"
android:layout_centerHorizontal="true"
android:contentDescription="#string/logo_caBB"
android:maxHeight="150dp"
android:src="#drawable/logo_cabb_100x51_or" />
<TextView
android:id="#+id/textViewCabbUrl"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentBottom="true"
android:layout_centerHorizontal="true"
android:text="#string/cabb_url" />
<ImageView
android:id="#+id/imageSite"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_above="#+id/textViewAppName"
android:contentDescription="#string/logo_Site"
android:scaleType="centerInside"
android:src="#drawable/image_guide_320x400" />
</RelativeLayout>
Here I can say tht the "imageSite" ImageView is well displayed, centered and occupies the whole area. Right.
Now I have a piece of code to replace this image in this same ImageView:
Bitmap imageSite = site.getSitePictureBitmap();
if (imageSite != null) {
imageGuide.setImageBitmap(imageSite);
}
If I only do that, despite en center_inside flag, the new bitmap, smaller and rectangular horizontally compare to the first one which is almost sqaure, the image is displayed very small on the bottom right corner of the ImageView, or the area taken by the ImageView, Idon't really know.
So I add this piece of code to resize it:
imageSite = site.getSitePictureBitmap(); // here I read the bitmap in a file.
if (imageSite != null) {
float maxWidth = imageGuide.getWidth();
float maxHeight = imageGuide.getHeight();
float width = imageSite.getWidth();
float height= imageSite.getHeight();
float hRatio = width / maxWidth;
float vRatio = height / maxHeight;
if (Math.abs(1 - hRatio) < Math.abs(1 - vRatio)) {
// We match horizontal available size
width = width / hRatio;
height = height / hRatio;
} else {
width = width / vRatio;
height = height / vRatio;
}
Bitmap reSizedBitmap = Bitmap.createScaledBitmap(imageSite, (int)width, (int)height, true);
imageGuide.setImageBitmap(reSizedBitmap);
So the image is now of the good width but as its vertical dimension is lower than the first picture, it's close to the textViewAppName. So as it's a rule for the ImageView in the layout description, I wonder if my image is not in the center of the ImageView in fact and my problem would come from the fact that the ImageView is now of a smaller height and doesn't fill up the whole space available at the top of the layout.
I also wondered if setting a new image doesn't reset the positionning flags. I didn't see that in the doc AFAIR but...
So I add this line after setImagebitmap() without success:
imageGuide.setScaleType(ScaleType.CENTER_INSIDE);
Can you tell me a bit more about ImageView behavior in this case and how to get my image vertically in the center of the available space. Do I have to calculate padding?
Regards,
Al
I want to put and ImageView with a large Y margin on my screen device, which would imply that part of the image would be out of screen, and then that the image would be cropped.
The problem is that Android is scaling the image all the time, so that it fits inside the screen, but I don't want that, I want the image to be cropped.
How can I force the ImageView to be cropped and not resized?
P.S. I tried all the possible ScaleType properties and none of them worked for me!
Code :
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="wrap_content"
android:layout_height="wrap_content" >
<ImageView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="200dp"
android:background="#drawable/my_image"
android:scaleType="centerCrop"
/>
</RelativeLayout>
Try replacing android:background with android:src.
First problem with your code is that you used:
android:background="#drawable/my_image"
instead of:
android:src="#drawable/my_image"
(with background none of the scaleType options work).
Now if this still doesn't help, you probably have to use scaleType="matrix" and then simply create a matrix that will do the required job. For example, let's assume that you want to:
keep the ratio of your image
scale the image so that the width parameter will equal X (for example: X can be the width of the screen)
make the top of the image visible (so crop the bottom of the image) - I'm assuming this is why centerCrop might not work for you
Here's the code:
ImageView imgView = (ImageView)findViewById(R.id.my_image_view);
Bitmap bitmap = BitmapFactory.decodeResource(getResources(),
R.drawable.my_image);
Matrix matrix = new Matrix();
// Let's assume X = 400
float scale = ((float) 400) / bitmap.getWidth();
matrix.setScale(scale, scale);
imgView.setImageMatrix(matrix);
And remember to make the necessary changes in the xml file.
Edit: partial answer
If both dimensions are set in the xml, it behaves as expected, for example
android:layout_width="250dp"
android:layout_height="250dp"
if one is left to wrap_content, it doesn't.
Original Post
Here is my layout:
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:orientation="horizontal" >
<ImageView
android:id="#+id/board"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:src="#drawable/board" />
</LinearLayout>
Why does the image I see on screen have the correct dimensions (screen height x screen height because it is a square bitmap and I set match_parent for height), BUT if I call ImageView.getWidth() and ImageView.getHeight() it gives me the screen dimensions?
Best regards
This is happening because of the reason I have provided in your earlier question here
https://stackoverflow.com/a/10183799/1244489
When you call getWidth() and getHeight(), it returns the size of your ImageView which in your case if you observe is the fullscreen size. Your source Image has been shrunk to fit the screen maintaining its aspect ratio but the ImageView isn't shrunk. To shrink it to the Image size, you need to provide the parameter
android:adjustViewBounds="true"
in your ImageView.
Found the answer here:
Fit image into ImageView, keep aspect ratio and then resize ImageView to image dimensions?
Here's the root of the problem: the ImageView doesn't size itself to the image dimensions, so we have to size it ourselves:
LinearLayout.LayoutParams params = (LinearLayout.LayoutParams) imageView.getLayoutParams();
params.width = width;
params.height = height;
imageView.setLayoutParams(params);
Because getWidth() and getHeight() are called from the View hierarchy which are screen dimensions. In fact, if the image was scaled using ImageView's scaletypes like fitCenter, the dimensions you get won't match the image at all. They will remain the pixel width and pixel height of the entire view and not just what was taken up by the image.
In Android, I defined an ImageView's layout_width to be fill_parent (which takes up the full width of the phone).
If the image I put to ImageView is bigger than the layout_width, Android will scale it, right? But what about the height? When Android scales the image, will it keep the aspect ratio?
What I find out is that there is some white space at the top and bottom of the ImageView when Android scales an image which is bigger than the ImageView. Is that true? If yes, how can I eliminate that white space?
Yes, by default Android will scale your image down to fit the ImageView, maintaining the aspect ratio. However, make sure you're setting the image to the ImageView using android:src="..." rather than android:background="...". src= makes it scale the image maintaining aspect ratio, but background= makes it scale and distort the image to make it fit exactly to the size of the ImageView. (You can use a background and a source at the same time though, which can be useful for things like displaying a frame around the main image, using just one ImageView.)
You should also see android:adjustViewBounds to make the ImageView resize itself to fit the rescaled image. For example, if you have a rectangular image in what would normally be a square ImageView, adjustViewBounds=true will make it resize the ImageView to be rectangular as well. This then affects how other Views are laid out around the ImageView.
Then as Samuh wrote, you can change the way it default scales images using the android:scaleType parameter. By the way, the easiest way to discover how this works would simply have been to experiment a bit yourself! Just remember to look at the layouts in the emulator itself (or an actual phone) as the preview in Eclipse is usually wrong.
See android:adjustViewBounds.
Set this to true if you want the ImageView to adjust its bounds to preserve the aspect ratio of its drawable.
To anyone else having this particular issue. You have an ImageView that you want to have a width of fill_parent and a height scaled proportionately:
Add these two attributes to your ImageView:
android:adjustViewBounds="true"
android:scaleType="centerCrop"
And set the ImageView width to fill_parent and height to wrap_content.
Also, if you don't want your image to be cropped, try this:
android:adjustViewBounds="true"
android:layout_centerInParent="true"
If you want an ImageView that both scales up and down while keeping the proper aspect ratio, add this to your XML:
android:adjustViewBounds="true"
android:scaleType="fitCenter"
Add this to your code:
// We need to adjust the height if the width of the bitmap is
// smaller than the view width, otherwise the image will be boxed.
final double viewWidthToBitmapWidthRatio = (double)image.getWidth() / (double)bitmap.getWidth();
image.getLayoutParams().height = (int) (bitmap.getHeight() * viewWidthToBitmapWidthRatio);
It took me a while to get this working, but this appears to work in the cases both where the image is smaller than the screen width and larger than the screen width, and it does not box the image.
This worked for me:
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:maxWidth="39dip"
android:scaleType="centerCrop"
android:adjustViewBounds ="true"
This is how it worked for me inside a ConstraintLayout:
<ImageView
android:id="#+id/myImg"
android:layout_width="300dp"
android:layout_height="300dp"
android:scaleType="fitCenter"
android:adjustViewBounds="true"/>
Then in code, I set the drawable as:
ImageView imgView = findViewById(R.id.myImg);
imgView.setImageDrawable(ResourcesCompat.getDrawable(getResources(), R.drawable.image_to_show, null));
This fits the image nicely according to its aspect ratio and keeps it in centre.
this solved my problem
android:adjustViewBounds="true"
android:scaleType="fitXY"
Take a look at ImageView.ScaleType to control and understand the way resizing happens in an ImageView. When the image is resized (while maintaining its aspect ratio), chances are that either the image's height or width becomes smaller than ImageView's dimensions.
Below code Working for scale image as aspect ratio:
Bitmap bitmapImage = BitmapFactory.decodeFile("Your path");
int nh = (int) ( bitmapImage.getHeight() * (512.0 / bitmapImage.getWidth()) );
Bitmap scaled = Bitmap.createScaledBitmap(bitmapImage, 512, nh, true);
your_imageview.setImageBitmap(scaled);
I have an image smaller than the screen. To have it stretched proportionally to the max and centered in the view I had to use the following code:
<ImageView
android:id="#+id/my_image"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:layout_centerInParent="true"
android:adjustViewBounds="true"
android:layout_weight="1"
android:scaleType="fitCenter" />
Have in mind though, that if you have a relative layout and have some elements set to be above or below the ImageView, they will be most likely overlapped by the image.
Use these properties in ImageView to keep aspect ratio:
android:adjustViewBounds="true"
android:scaleType="fitXY"
<ImageView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:adjustViewBounds="true"
android:scaleType="fitXY"
/>
If image quality decreases in:
use
android:adjustViewBounds="true"
instead of
android:adjustViewBounds="true"
android:scaleType="fitXY"
For anyone of you who wants the image to fit exact the imageview with proper scaling and no cropping use
imageView.setScaleType(ScaleType.FIT_XY);
where imageView is the view representing your ImageView
You can calculate screen width. And you can scale bitmap.
public static float getScreenWidth(Activity activity) {
Display display = activity.getWindowManager().getDefaultDisplay();
DisplayMetrics outMetrics = new DisplayMetrics();
display.getMetrics(outMetrics);
float pxWidth = outMetrics.widthPixels;
return pxWidth;
}
calculate screen width and scaled image height by screen width.
float screenWidth=getScreenWidth(act)
float newHeight = screenWidth;
if (bitmap.getWidth() != 0 && bitmap.getHeight() != 0) {
newHeight = (screenWidth * bitmap.getHeight()) / bitmap.getWidth();
}
After you can scale bitmap.
Bitmap scaledBitmap=Bitmap.createScaledBitmap(bitmap, (int) screenWidth, (int) newHeight, true);
When doing this programmatically, be sure to call the setters in the correct order:
imageView.setAdjustViewBounds(true)
imageView.setScaleType(ImageView.ScaleType.CENTER_CROP)
If you want your image occupy the maximum possible space then the best option would be
android:layout_weight="1"
android:scaleType="fitCenter"
Yo don't need any java code. You just have to :
<ImageView
android:layout_width="match_parent"
android:layout_height="match_parent"
android:adjustViewBounds="true"
android:scaleType="centerCrop" />
The key is in the match parent for width and height
I use this:
<ImageView
android:id="#+id/logo"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:layout_centerInParent="true"
android:scaleType="centerInside"
android:src="#drawable/logo" />
Try using android:layout_gravity for ImageView:
android:layout_width="wrap_content"
android:layout_height="0dp"
android:layout_gravity="center_vertical|center_horizontal"
android:layout_weight="1"
The example above worked for me.
I have an algorithm to scale a bitmap to bestFit the container dimensions, maintaining its aspect ratio. Please find my solution here
Hope this helps someone down the lane!
Pass your ImageView and based on screen height and width you can make it
public void setScaleImage(EventAssetValueListenerView view){
// Get the ImageView and its bitmap
Drawable drawing = view.getDrawable();
Bitmap bitmap = ((BitmapDrawable)drawing).getBitmap();
// Get current dimensions
int width = bitmap.getWidth();
int height = bitmap.getHeight();
float xScale = ((float) 4) / width;
float yScale = ((float) 4) / height;
float scale = (xScale <= yScale) ? xScale : yScale;
Matrix matrix = new Matrix();
matrix.postScale(scale, scale);
Bitmap scaledBitmap = Bitmap.createBitmap(bitmap, 0, 0, width, height, matrix, true);
BitmapDrawable result = new BitmapDrawable(scaledBitmap);
width = scaledBitmap.getWidth();
height = scaledBitmap.getHeight();
view.setImageDrawable(result);
LinearLayout.LayoutParams params = (LinearLayout.LayoutParams) view.getLayoutParams();
params.width = width;
params.height = height;
view.setLayoutParams(params);
}
Programatically apply aspect ratio to Imageview:
aspectRatio = imageWidth/imageHeight
ratioOfWidth = imageWidth/maxWidth
ratioOfHeight = imageHeight/maxHeight
if(ratioOfWidth > ratioOfHeight){
imageWidth = maxWidth
imageHeight = imageWidth/aspectRatio
} else if(ratioOfHeight > ratioOfWidth){
imageHeight = maxHeight
imageWidth = imageHeight * aspectRatio
}
After that you can use scaled bitmap to image view
Bitmap scaledBitmap= Bitmap.createScaledBitmap(bitmap, (int) imageWidth , (int) imageHeight , true);
in case of using cardviewfor rounding imageview and fixed android:layout_height for header this worked for me to load image with Glide
<?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="220dp"
xmlns:card_view="http://schemas.android.com/apk/res-auto"
>
<android.support.v7.widget.CardView
android:id="#+id/card_view"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center|top"
card_view:cardBackgroundColor="#color/colorPrimary"
card_view:cardCornerRadius="10dp"
card_view:cardElevation="10dp"
card_view:cardPreventCornerOverlap="false"
card_view:cardUseCompatPadding="true">
<ImageView
android:adjustViewBounds="true"
android:maxHeight="220dp"
android:id="#+id/iv_full"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:scaleType="fitCenter"/>
</android.support.v7.widget.CardView>
</FrameLayout>
You can scale image that will also reduce the size of your image.
There is a library for it you can download and use it.
https://github.com/niraj124124/Images-Files-scale-and-compress.git
How to use
1)Import the compressor-v1.0. jar to your project.
2)Add the below sample code to test.
ResizeLimiter resize = ImageResizer.build();
resize.scale("inputImagePath", "outputImagePath",imageWidth, imageHeight);
Many more methods are there according to your requirement
Quick answer:
<ImageView
android:id="#+id/imageView"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:scaleType="center"
android:src="#drawable/yourImage"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
imageView.setImageBitmap(Bitmap.createScaledBitmap(bitmap, 130, 110, false));