Is there a way to get the dimensions of the image currently set in the ImageButton? I'm trying to achieve this.
I have a ImageButton with a default pic of 36 x 36. I then select an image of size say 200 x 200. I wanna call something like:
imageButton.setImageBitmap(Bitmap.createScaledBitmap(
bitmap, 36, 36, true));
to shrink the image to 36 x 36. Reason why I want to get the original image size is to cater for hdpi, mdpi and ldpi so I can set dimensions of the bitmap to 36 x 36, 24 x 24 and 18 x 18 respectively before adding it to the ImageButton. Any ideas?
Oh man, I got the answer after randomly fiddling with the code:
imageButton.getDrawable().getBounds().height();
imageButton.getDrawable().getBounds().width();
Try this code -
imageButton.getDrawable().getBounds().height();
imageButton.getDrawable().getBounds().width();
Maurice's answer didn't quite work for me, as I would frequently get 0 back, resulting in an Exception being thrown whenever trying to generate the scaled bitmap:
IllegalArgumentException: width and height must be > 0
I found a few other options if it helps anyone else.
Option 1
The imageButton is a View which means we can get the LayoutParams and take advantage of the built-in height and width properties. I found this from this other SO answer.
imageButton.getLayoutParams().width;
imageButton.getLayoutParams().height;
Option 2
Have our imageButton come from a Class which extends ImageButton, and then override View#onSizeChanged.
Option 3
Get the drawing rectangle on the view and use the width() and height() methods to get the dimensions:
android.graphics.Rect r = new android.graphics.Rect();
imageButton.getDrawingRect(r);
int rectW = r.width();
int rectH = r.height();
Combination
My final code ended up combining the three and selecting the max. I am doing this because I will get different results, depending on which phase the application is in (like when the View has not been fully drawn).
int targetW = imageButton.getDrawable().getBounds().width();
int targetH = imageButton.getDrawable().getBounds().height();
Log.d(TAG, "Calculated the Drawable ImageButton's height and width to be: "+targetH+", "+targetW);
int layoutW = imageButton.getLayoutParams().width;
int layoutH = imageButton.getLayoutParams().height;
Log.e(TAG, "Calculated the ImageButton's layout height and width to be: "+targetH+", "+targetW);
targetW = Math.max(targetW, layoutW);
targetH = Math.max(targetW, layoutH);
android.graphics.Rect r = new android.graphics.Rect();
imageButton.getDrawingRect(r);
int rectW = r.width();
int rectH = r.height();
Log.d(TAG, "Calculated the ImageButton's getDrawingRect to be: "+rectW+", "+rectH);
targetW = Math.max(targetW, rectW);
targetH = Math.max(targetH, rectH);
Log.d(TAG, "Requesting a scaled Bitmap of height and width: "+targetH+", "+targetW);
Bitmap scaledBmp = Bitmap.createScaledBitmap(bitmap, targetW, targetH, true);
Related
Is it possible to assign width and height to RadioButton in Android programmatically? I know we can do it by using scaleX and scaleY properties. What I am looking for is, if user gives a width and height in int, how can we apply to the RadioButton?
Try this:
myRadioButton.getButtonDrawable().setBounds(/* play around with the bounds */);
The documentation on the Drawable class says this is how you change a Drawable's size. Unfortunately, it's not really clear how it works, so you'll need to play around.
Since RadioButton, inherits from TextView, you can use myRadioButton.setHeight(int pixels) and .setWidth(int pixels) to set the size of the entire button area, but not the text nor the selection circle. To change the size of the content but not the overall area, you can use .setScaleX(float scale) and .setScaleY() you will change the text and selection circle, but not the button area.
So to change both the button area and the size of its contents:
int desiredWidth = 500; // Set to your desired width.
int currentWidth = radioButton.getWidth();
radioButton.setScaleX(desiredWidth / currentWidth);
radioButton.setWidth(desiredWidth);
And likewise for the height.
If you want to maintain the aspect ratio, set just the desired width and then:
desired_height = desired_width * current_height / current_width
Like this:
int desiredWidth = 500;
int currentHeight = radioButton.getHeight();
int currentWidth = radioButton.getWidth();
int desiredHeight = desiredWidth * currentHeight / currentWidth;
radioButton.setScaleY(desiredHeight / currentHeight);
radioButton.setHeight(desiredHeight);
radioButton.setScaleX(desiredWidth / currentWidth);
radioButton.setWidth(desiredWidth);
It appears that the scale is adjusted from the center, without adjusting the position, so you might have to change the position (maybe this will be moot if you use a ConstraintLayout--with a LinearLayout my buttons bled off the screen when I resized them this way).
I have a square ImageView which displays pictures of varying dimensions. I want to always maintain the original aspect ratio of the pictures and have no margin around the image (so that the image takes up the whole ImageView). For this, I am using the centerCrop scaleType on the ImageView. However, I want to make it so that if the top and bottom of the image are cut off (i.e.: the image is taller than it is wide), the image gets pulled towards the bottom of the container. So instead of having equal amounts of pixels cropped at the top and bottom, the image is flush with the top and sides of the ImageView and the bottom of the image has twice as much cropped off. Is this possible in xml, if not, is there a java solution?
You won't be able to do that with a regular ImageView and it's properties in xml. You can accomplish that with a proper scaleType Matrix, but tbh writing it is a pain in the ass. I'd suggest you use a respected library that can handle this easily. For example CropImageView.
You probably can't do this in layout. But it's possible with a piece of code like this:
final ImageView image = (ImageView) findViewById(R.id.image);
// Proposing that the ImageView's drawable was set
final int width = image.getDrawable().getIntrinsicWidth();
final int height = image.getDrawable().getIntrinsicHeight();
if (width < height) {
// This is just one of possible ways to get a measured View size
image.getViewTreeObserver().addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {
#Override
public void onGlobalLayout() {
int measuredSize = image.getMeasuredWidth();
int offset = (int) ((float) measuredSize * (height - width) / width / 2);
image.setPadding(0, offset, 0, -offset);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN) {
image.getViewTreeObserver().removeOnGlobalLayoutListener(this);
} else {
image.getViewTreeObserver().removeGlobalOnLayoutListener(this);
}
}
});
}
Note that if your ImageView has predefined size (likely it has) then you need to put this size to dimen resources and the code will be even simpler:
ImageView image = (ImageView) findViewById(R.id.image2);
// For sure also proposing that the ImageView's drawable was set
int width = image.getDrawable().getIntrinsicWidth();
int height = image.getDrawable().getIntrinsicHeight();
if (width < height) {
int imageSize = getResources().getDimensionPixelSize(R.dimen.image_size);
int offset = (int) ((float) imageSize * (height - width) / width / 2);
image.setPadding(0, offset, 0, -offset);
}
See also:
findViewById()
getResources()
So I have been experimenting today with making an Android Application, but I have tried the LineairLayout to make a welcom screen for my application, but I cannot get it right..
So I tried RelativeLayout and I saw I can move my ImageViews and buttons to everywhere. So my question is if I will move the items to places like center, bottom left and bottom right. Would this be a problem or all phones since not all phones have the same dimensions?
public class WelcomeActivity extends Activity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.welcome_screen_relative);
final ImageView logo = (ImageView) findViewById(R.id.myImageView);
DisplayMetrics metrics = Resources.getSystem().getDisplayMetrics();
int displayHeight = metrics.heightPixels;
int displayWidth = metrics.widthPixels;
float scaledDensity = metrics.scaledDensity;
BitmapFactory.Options dimensions = new BitmapFactory.Options();
dimensions.inJustDecodeBounds = true;
Bitmap mBitmap = BitmapFactory.decodeResource(getResources(), R.drawable.log, dimensions);
int imageHeight = dimensions.outHeight;
int imageWidth = dimensions.outWidth;
float percentageToMoveViewDown = (float) 20.0;
float viewY_float = (float) ((displayHeight / 100.0) * percentageToMoveViewDown);
int viewY_int = Math.round(viewY_float);
RelativeLayout.LayoutParams view_Layout_params = new RelativeLayout.LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT);
view_Layout_params.topMargin = viewY_int;
logo.setLayoutParams(view_Layout_params);
logo.getLayoutParams().height = imageHeight;
logo.getLayoutParams().width = imageWidth;
}
Thats depends. If you give objects a fixed size of course it will. for dp/dpi make sure to test it in Emu or real devices. You can also create density and orientation specific layout to support many screens. Consider that there are not only changes in size but also aspect ration and resolution and DPI.
For most apps RelativeLayout is might be the right approach.
You can read an excelent article about it here: http://developer.android.com/guide/practices/screens_support.html
If the items have fixed sizes you always will have trouble with some phones. For the big ones it may be too small, for the small ones too big...
In my experience Androids small/normal/large screens won't help you much for configuring, since the differences are just too big.
If you want to make sure everything sits where it belongs to, you could get the device metrics. That way you don't even need to rely on center, but you can work with percentages to place everything where you want it to be. Plus you can set the sizes in percentage, which is great. Like you could say I want a button thats width is 50% of the screen, no matter how large the screen is. Its more work (maybe even overkill), but I really like that approach. Once you figured it out its basically just a bit copy paste at the start of your classes.
Example:
DisplayMetrics metrics = Resources.getSystem().getDisplayMetrics();
int displayHeight = metrics.heightPixels;
int displayWidth = metrics.widthPixels;
float scaledDensity = metrics.scaledDensity;
//move some View 20% down:
float percentageToMoveViewDown = (float) 20.0;
float viewY_float = (float) ((displayHeight / 100.0) * percentageToMoveViewDown);
int viewY_int = Math.round(viewY_float);
RelativeLayout.LayoutParams view_Layout_params = new RelativeLayout.LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT);
view_Layout_params.topMargin = viewY_int;
view.setLayoutParams(view_Layout_params);
//even works with text size for a TextView:
float percentageToResizeTextViewTextSize = (float) 3.1;
float textViewTextSize_float = (float) ((displayHeight / 100.0) * percentageToResizeTextViewTextSize);
int textViewTextSize_int = Math.round(textViewTextSize_float / scaledDensity);
textView.setTextSize(textViewTextSize_int);
Just a side note for the overkill thing: This should be only necessary if you want to support small devices (they mostly run something like android 2.3, but still are sold as budget phones) and big devices as well, but the trouble with the big ones is not as big as the trouble with the small ones. I personally rather put more effort in it than less, you never know.
Edit: ImageView by code
The easiest way is to do it hybridly, using xml and code. Note that you will have to change width and height if you set it to 0 in xml like in the following example.
Just place it in the xml where you would anyways, somewhere in your RelativeLayout.
In your xml:
<ImageView
android:id="#+id/myImageView"
android:layout_width="0dp"
android:layout_height="0dp" />
In your Code:
ImageView myImageView = (ImageView)findViewById(R.id.myImageView);
You now can work with that myImageView as I did it with view and textView. You can even set the image right here in code.
This imageView with the size of 0,0 is now placed where it would have been before. Now you could set the width to like 50% of the screenwidth and the height to...lets say 40% of the screen height. Then You would need to place it. If you want to center it you know that there must be 25% of the screen on each side, so you can add 25% as left and right margin.
Edit 2: maintain original imagesize
If you want to keep the original size of a image in your drawables, you can get its width and height like this:
BitmapFactory.Options dimensions = new BitmapFactory.Options();
dimensions.inJustDecodeBounds = true;
Bitmap mBitmap = BitmapFactory.decodeResource(getResources(), R.drawable.yourImageName, dimensions);
int imageHeight = dimensions.outHeight;
int imageWidth = dimensions.outWidth;
Now that you have that, you could use it to calculate the aspect ratio to keep it.
Now since you know the devices width and height, you can easily calculate how much of the screen this image will need.(imageheight/screenheight*100 = your percentage of the screen you want the imageviews height to be). So the Height you set to the imageview would be displayHeight / 100 * (imageHeight / displayHeight * 100).
How to place that?
Now if you take a Screenheight of 100 and a imageheight of 80 you get 80%. You would now take this percentage and divide it from 100. Divide that /2 and you know how much space you would have as top and bottom margins if you wanted it to be placed in the middle of the screen (you would have to do the same for width).
Caution: If you don't want it to be relative to the screensize but the original size, that percentage approach is kind of pointless. If you do to your image what I just described, it may still be too big for small devices and too small for big ones. Instead you could think about what percentage would look good in proportion to the rest of the stuff on the screen and resize it to that, since it would have that relative size on all devices.
Edit 3:
Since you load the image in original size, it will be small on big devices if it is a small image.
//first you need to know your aspect ratio.
float ratio = imageWidth / imageHeight;
//lets say you wanted the image to be 50% of the screen:
float percentageToResizeImageTo = (float) 50.0;
float imageX_float = (float) ((displayHeight / 100.0) * percentageToResizeImageTo);
int imageX_int = Math.round(imageX_float);
//now you know how much 50% of the screen is
imageWidth = imageX_int;
imageHeight = imageWidth * ratio;
RelativeLayout.LayoutParams view_Layout_params = new RelativeLayout.LayoutParams(imageHeight, imageWidth);
view_Layout_params.topMargin = viewY_int;
logo.setLayoutParams(view_Layout_params);
logo.setScaleType(ImageView.ScaleType.Fit_XY);
I'm trying to dynamically build a layout, so it scales and looks more or less identical on all screen sizes and resolutions. I do this by programmatically placing my views inside a RelativeLayout and scaling everything according to a certain factor.
I noticed something strange when moving an ImageView around though, the bigger the values on margins get, the smaller the ImageView gets. This gets really annoying when trying to get things at right place and size.
private void initializeObjects() {
Display display = getWindowManager().getDefaultDisplay();
Point screenSize = new Point();
display.getSize(screenSize);
float scale = screenSize.x / ( (screenSize.x < screenSize.y) ? 480 : 800 ); // Scale according to Galaxy S II resolution
RelativeLayout screenLayout = (RelativeLayout) findViewById(R.id.main_layout);
mRobotView = new ImageView(getApplicationContext());
mRobotView.setImageResource(R.drawable.soomla_logo_new); // a 743 x 720 png
mRobotView.setScaleX(scale * 100 / 743); // Make sure the image is 100 "units" in size
mRobotView.setScaleY(scale * 100 / 720);
mRobotView.setPivotX(scale * 100 / 743); // reset the image origin according to scale
mRobotView.setPivotY(scale * 100 / 720);
RelativeLayout.LayoutParams robotParams = new RelativeLayout.LayoutParams(743, 720);
robotParams.leftMargin = 0xDEADBEEF; // The bigger these get the smaller the view gets
robotParams.topMargin = 0xDEADBEEF;
screenLayout.addView(mRobotView, robotParams);
}
Any idea what's causing this?
Use
android:layout_height="720px"
android:layout_height="743px"
in the main_layout.xml to have the image not shrinked
This question already has answers here:
How to get the width and height of an android.widget.ImageView?
(10 answers)
Closed 6 years ago.
What is the best way to retrieve the dimensions of the Drawable in an ImageView?
My ImageView has an Init-Method where I create the ImageView:
private void init() {
coverImg = new ImageView(context);
coverImg.setScaleType(ScaleType.FIT_START);
coverImg.setImageDrawable(getResources().getDrawable(R.drawable.store_blind_cover));
addView(coverImg);
}
At some point during the layout oder measure process I need the exact dimensions of the Drawable to adjust the rest of my Components around it.
coverImg.getHeight() and coverImg.getMeasuredHeight() don't return the results that I need and if I use coverImg.getDrawable().getBounds() I get the dimensions before it was scaled by the ImageView.
Thanks for your help!
Just tried this out and it works for me:
int finalHeight, finalWidth;
final ImageView iv = (ImageView)findViewById(R.id.scaled_image);
final TextView tv = (TextView)findViewById(R.id.size_label);
ViewTreeObserver vto = iv.getViewTreeObserver();
vto.addOnPreDrawListener(new ViewTreeObserver.OnPreDrawListener() {
public boolean onPreDraw() {
// Remove after the first run so it doesn't fire forever
iv.getViewTreeObserver().removeOnPreDrawListener(this);
finalHeight = iv.getMeasuredHeight();
finalWidth = iv.getMeasuredWidth();
tv.setText("Height: " + finalHeight + " Width: " + finalWidth);
return true;
}
});
The ViewTreeObserver will let you monitor the layout just prior to drawing it (i.e. everything has been measured already) and from here you can get the scaled measurements from the ImageView.
Call getIntrinsicHeight and getIntrinsicWidth on the drawable.
public int getIntrinsicHeight ()
Since: API Level 1
Return the intrinsic height of the underlying drawable object.
Returns -1 if it has no intrinsic height, such as with a solid color.
public int getIntrinsicWidth ()
Since: API Level 1
Return the intrinsic width of the underlying drawable object.
Returns -1 if it has no intrinsic width, such as with a solid color.
http://developer.android.com/reference/android/graphics/drawable/Drawable.html#getIntrinsicHeight()
This is the size of the original drawable. I think this is what you want.
The most reliable and powerful way to get drawable dimensions for me has been to use BitmapFactory to decode a Bitmap. It's very flexible - it can decode images from a drawable resource, file, or other different sources.
Here's how to get dimensions from a drawable resource with BitmapFactory:
BitmapFactory.Options o = new BitmapFactory.Options();
o.inTargetDensity = DisplayMetrics.DENSITY_DEFAULT;
Bitmap bmp = BitmapFactory.decodeResource(activity.getResources(),
R.drawable.sample_image, o);
int w = bmp.getWidth();
int h = bmp.getHeight();
Be careful if you use multiple density drawable folders under res, and make sure you specify inTargetDensity on your BitmapFactory.Options to get the drawable of the density you want.
Efficient way to get Width & Height of Drawable:
Drawable drawable = getResources().getDrawable(R.drawable.ic_home);
int width = drawable.getIntrinsicWidth();
int height = drawable.getIntrinsicHeight();
Log.i("Drawable dimension : W-H", width+"-"+height);
Hope this will help you.
this solved my problem. It decode the size of image boundary without really load the whole image.
BitmapFactory.Options o = new BitmapFactory.Options();
o.inJustDecodeBounds = true;
Bitmap bmp = BitmapFactory.decodeResource(this.getResources(), R.drawable.img , o);
int w = o.outWidth;
int h = o.outHeight;