put the Element on certain points on the background in a RelativeLayout - android

I have an image, I want to put a TextView on a certain point(on the brown rectangle) in different devices with different screen sizes. My image is below:
CAUTION:the scaleType of the ImageView is CenterCrop
in image below I show where I want to put the TextView:
And this is my xml:
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
>
<ImageView
android:layout_width="match_parent"
android:layout_height="match_parent"
android:src="#drawable/startpage"<!-- my background-->
android:scaleType="centerCrop"
/>
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="TextView"
android:textColor="#fff"/>
</RelativeLayout>

There's tons of options how to do that, but seeing your pics I'd simply make my TextView aligned to top-left corner and set its layout margin to right values in dp (which I'd simply figure out in any graphics program).

There are several ways. I am quite new so someone with more knowledge would most likely have a better answer. But, you can try to align with Relative Layout. Or you can use a layout gravity to change it so that it "gravitates" towards where you want it to be.

I suggest you to start with also draw 9-patch which is a tool that helps u to select where do u want the content to fit inside the picture.
The Draw 9-patch tool is a WYSIWYG editor that allows you to create
bitmap images that automatically resize to accommodate the contents of
the view and the size of the screen.
After that you will need to check alignment and such stuff. like top left, padding-top... etc

At last, I found it myself, see these java codes:
I find the display width and height, then calculate the scale, the according to the scale I scale the margins.
#Bind(R.id.name_tv)TextView nameTV;
public final static float bgWidth = 768;
public final static float bgHeight = 1136;
public float tVsRightMargin = 123;
public float nameTVtopMargin = 314;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
ResourceManager.setActivity(this);
setContentView(R.layout.main);
ButterKnife.bind(this);
DisplayMetrics displayMetrics = new DisplayMetrics();
getWindowManager().getDefaultDisplay().getMetrics(displayMetrics);
int displayWidth = displayMetrics.widthPixels;
int displayHeight = displayMetrics.heightPixels;
Log.v("MainActivity","displayWidth: "+displayWidth);
Log.v("MainActivity", "displayHeight: " + displayHeight);
float scale = Math.max(displayWidth/bgWidth, displayHeight/bgHeight);
Log.v("MainActivity", "scale: "+scale);
float bgScaledWidth = scale*bgWidth;
float bgScaledHeight = scale*bgHeight;
tVsRightMargin *= scale;
nameTVtopMargin *= scale;
if(bgScaledWidth>displayWidth) {
tVsRightMargin -= ((bgScaledWidth - displayWidth) / 2f);
}
if(bgScaledHeight>displayHeight){
nameTVtopMargin -= ((bgScaledHeight-displayHeight)/2f);
}
nameTV.setText("محمد");
nameTV.setTypeface(ResourceManager.getTypeface());
Log.v("MainActivity", "top margin: " + nameTVtopMargin);
Log.v("MainActivity", "right margin: " + tVsRightMargin);
((RelativeLayout.LayoutParams) nameTV.getLayoutParams()).setMargins(0, (int) nameTVtopMargin, (int) tVsRightMargin, 0);
}

Related

How to get actual image width/height from ImageView?

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="#+id/rl_root"
android:layout_width="match_parent"
android:layout_height="match_parent">
<ImageView
android:id="#+id/myImage"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:adjustViewBounds="true"
android:background="#android:color/black"
android:src="#drawable/image2" />
<View
android:id="#+id/view_clickable_first"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:background="#aa000000" />
</RelativeLayout>
I want to make a small part of image in Imageview(myImage) clickable after getting coordinates. Its working fine for me.
Now I want to get the functionality of pinch zoom on this image. As I zoom in, clickable area along with the image will also zoom and accordingly.
My problem is that, I want to get height of image in ImageView (excluding black spaces in top and bottom. As ImageView is set to match parent, Image is showing in center of the screen in landscape mode). EveryTime I am getting height of imageview.
My code for getting height of image and imageview:
int imagWidth = imageView.getWidth();
int h = imageView.getHeight();
int w = imageView.getDrawable().getIntrinsicWidth();
int imagHeight = imageView.getDrawable().getIntrinsicHeight();
Log.e("height", "Image height" + imagHeight + "\n" + "Imageview height" + h);
So as per calculation:
Image height= 882
Imageview height = 672
Work for me
imgView.getViewTreeObserver().addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {
#Override
public void onGlobalLayout() {
// Ensure you call it only once :
imgView.getViewTreeObserver().removeGlobalOnLayoutListener(this);
// Here you can get the size :)
width = imgView.getWidth();
height = imgView.getHeight();
}
});
To get the height of an image in the image view you can simply do:
int width = imgView.getDrawable().getIntrinsicWidth();
int height = imgView.getDrawable().getIntrinsicHeight();
This will return the 'intrinsic' values of height and width. (these values are the values of the image you are loading into the image view as is without any scaling. you can adjust these values to match any scaling that you may have applied) To adjust values for scaling (given you know its in landscape mode) the following should work :
int width = imgView.getDrawable().getIntrinsicWidth();
int height = imgView.getDrawable().getIntrinsicHeight();
double scale = ((double)imgeView.getWidth())/width
int final_height = Math.toIntExact(Math.round(scale * height));
now final_height is the height of the displayed image.
Use these below code with ViewTreeObserver
int yourImageViewWidth , yourImageViewHeight;
ImageView y = (ImageView)findViewById(R.id.scaled_image);
ViewTreeObserver vto = yourImageView.getViewTreeObserver();
vto.addOnPreDrawListener(new ViewTreeObserver.OnPreDrawListener() {
public boolean onPreDraw() {
yourImageView.getViewTreeObserver().removeOnPreDrawListener(this);
yourImageViewHeight = yourImageView.getMeasuredHeight();
yourImageViewWidth = yourImageView.getMeasuredWidth();
Log.d("Height: " + yourImageViewHeight + " Width: " + yourImageViewWidth);
return true;
}
});

Scale ImageView and clip bottom only when outside parent view?

how does one scale an ImageView, yet still have it clip (bottom only) when it/parts of it are outside its parent view?
My code;
XML has 3 elements; image in raw size, view 200px high, view 150px high.
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="1000px"
android:layout_height="850px"
android:background="#FFFEC6"
android:orientation="vertical">
<!-- single image in raw size -->
<ImageView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:src="#drawable/fauxcard"
/>
<!-- should be SCALED with NO CLIPPING -->
<RelativeLayout
android:id="#+id/Wrapper1"
android:layout_width="1000px"
android:layout_height="200px"
android:background="#cccccc">
</RelativeLayout>
<!-- should be SCALED with the BOTTOM CLIPPED -->
<RelativeLayout
android:id="#+id/Wrapper2"
android:layout_width="1000px"
android:layout_height="150px"
android:background="#C6FFD1"
android:clipChildren="true">
</RelativeLayout>
</LinearLayout>
java;
RelativeLayout r1 = (RelativeLayout) findViewById(R.id.Wrapper1);
RelativeLayout r2 = (RelativeLayout) findViewById(R.id.Wrapper2);
int marginLeft = 0;
for (int i = 0; i < 10; i++)
{
// IV 1 - the parent view for these is the correct 200 high, so these will be unclipped/unscaled
ImageView myImg1 = new ImageView(this);
myImg1.setImageResource(R.drawable.fauxcard);
RelativeLayout.LayoutParams layout1 = new RelativeLayout.LayoutParams(100, 200);
layout1.setMargins(marginLeft, 0, 0, 0);
r1.addView(myImg1, layout1);
// IV 2 - the parent view for these is NOT high enough (only 150 high), so I want these SCALED but CLIPPED (bottom of image clipped)
ImageView myImg2 = new ImageView(this);
myImg2.setImageResource(R.drawable.fauxcard);
// scaling
// myImg2.setScaleType(ImageView.ScaleType.CENTER); // NOT scaled - clipped
// myImg2.setScaleType(ImageView.ScaleType.CENTER_INSIDE); // scaled - NOT clipped
myImg2.setScaleType(ImageView.ScaleType.CENTER_CROP); // scaled - clipped at TOP and bottom
// myImg2.setScaleType(ImageView.ScaleType.FIT_END); // scaled TOO MUCH - clip not needed
// myImg2.setScaleType(ImageView.ScaleType.FIT_START); // scaled TOO MUCH - clip not needed
// myImg2.setScaleType(ImageView.ScaleType.FIT_CENTER); // scaled TOO MUCH - clip not needed
// myImg2.setScaleType(ImageView.ScaleType.FIT_XY); // scaled incorrect ratio - clip not needed
// myImg2.setScaleType(ImageView.ScaleType.MATRIX); // NOT scaled - clipped
RelativeLayout.LayoutParams layout2 = new RelativeLayout.LayoutParams(100, 200);
layout2.setMargins(marginLeft, 0, 0, 0);
r2.addView(myImg2, layout2);
// I am using marginLeft as my real scenario is more complex - there are varying gaps between the images based on other logic
// the important issue is CLIPPING the images whilst scaling them
marginLeft += 100;
}
To both of the RelativeLayouts I'm adding 10 images. I want both sets of images to be scaled the same, but as the 2nd RL isn't high enough I want those images CLIPPED (the bottom of the image gone).
I've tried all ScaleTypes, but none of them achieve this. The closest is CENTER_CROP, which has the correct scaling, but both the top and bottom are clipped (and, again, I just want the bottom clipped).
Here's a image;
https://imgur.com/a/QLJkm
put this code in viewtreeobserver or you can have custom imageview
Matrix matrix = imageView.getImageMatrix();
float scale;
final int viewWidth = getWidth() - getPaddingLeft() - getPaddingRight();
final int drawableWidth = drawable.getIntrinsicWidth();
scale = (float) viewWidth / (float) drawableWidth;
matrix.setScale(scale, scale);
setImageMatrix(matrix);

How the View are occupy space on screen

I want to calculate how much views are displayed on screen at a time if view width is fixed. For that I get one Layout add some views in it with fixed size and run it.
But as per my calculation I get wrong number of child to displayed on screen as it shows on screen.
Please tell me where I am wrong?
Here is my code...
In Activity ...
----
LinearLayout featured_listlayout_horizontallayout=(LinearLayout)findViewById(R.id.featured_listlayout_horizontallayout);
LayoutInflater inflater=LayoutInflater.from(getApplicationContext());
for(int i=0;i<20;i++){
LinearLayout childItem=(LinearLayout)inflater.inflate(R.layout.childitemlayout,null);
Button btn=(Button)childItem.findViewById(R.id.btn);
btn.setText("Item"+(i+1));
featured_listlayout_horizontallayout.addView(childItem);
}
DisplayMetrics dm = new DisplayMetrics();
getWindowManager().getDefaultDisplay().getMetrics(dm);
final int height = dm.heightPixels;
float screenWidth = dm.widthPixels;//Screen Width in pixel
float itemWidth=getResources().getDimension(R.dimen.featured_text);//itemWidth in DP
itemWidth=convertDpToPixel(itemWidth, getApplicationContext());// convert itemWidth into pixel
System.out.println("screenWidth "+screenWidth+" itemWidth "+itemWidth);
float noOfItem=screenWidth/itemWidth;
System.out.println("noOfItem "+noOfItem);
-----
convertPixelsToDp method:
public float convertPixelsToDp(float px,Context context){
Resources resources = context.getResources();
DisplayMetrics metrics = resources.getDisplayMetrics();
float dp = px / (metrics.densityDpi / 160f);
return dp;
}
convertDpToPixel method:
public float convertDpToPixel(float dp,Context context){
Resources resources = context.getResources();
DisplayMetrics metrics = resources.getDisplayMetrics();
float px = dp * (metrics.densityDpi/160f);
return px;
}
activity_main.xml
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MainActivity" >
<HorizontalScrollView
android:layout_width="match_parent"
android:layout_height="wrap_content" >
<LinearLayout
android:id="#+id/featured_listlayout_horizontallayout"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:paddingBottom="5dp" >
</LinearLayout>
</HorizontalScrollView>
</RelativeLayout>
childitemlayout.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="#dimen/featured_text"
android:layout_height="#dimen/featured_image"
android:orientation="vertical"
android:background="#0000ff">
<Button android:id="#+id/btn"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:text="Button"
android:background="#ff00ff"/>
</LinearLayout>
dimen.xml
<?xml version="1.0" encoding="utf-8"?>
<resources>
<dimen name="featured_text">80dp</dimen>
<dimen name="featured_image">60dp</dimen>
</resources>
But as per my calculation I get wrong number of child to displayed on
screen as it shows on screen.
You get the width of the screen in pixels:
float screenWidth = dm.widthPixels;
and for the width of the items you get the width in pixels but you also transform it into dp:
float itemWidth=getResources().getDimension(R.dimen.featured_text);
itemWidth=convertPixelsToDp(itemWidth, getApplicationContext());
And then you try to use those two values together.
Either use pixels or dp.
Edit 2:
You should really read about the inflate() methods of the LayoutInflater class. You need to inflate the views with the proper LayoutParams and this is done by providing the ViewGroup that will be the parent of the inflated layout file. So you need to do:
LinearLayout childItem = (LinearLayout) inflater.inflate(
R.layout.aaaaaaaaaaaa, featured_listlayout_horizontallayout, false);
If you don't do this, your inflated views will not have the set size on them(as you have probably seen they will wrap their content). After you've done the modification above and you want to find out the number of children that wopuld be visible(completely or partially) before you actually add them in the layout(using the dimension you set in the xml layout) you just divide the screen width to the dimension from the resources:
int screenWidth = dm.widthPixels;
int itemWidth=getResources().getDimension(R.dimen.featured_text);
int noOfItem=screenWidth/itemWidth;
// if we have a remainder from the division it means there is extra space
// so we need to check if we have more items so there is another child partially showing
int rem = screenWidth % itemWidth;
if (rem != 0) {
noOfItem += 1;
}
Edit 1:
Your current code will not work and you didn't understand my answer. dm.widthPixels returns the screen width(which your HorizontalScrollView fills) in pixels. getResources().getDimension(R.dimen.featured_text) will return the value of that dimension resource in pixels. There is no need for methods to transform those values, just use them directly. Even so your code will not work right as you wanted because you don't take care of assigning the proper LayoutParams to your views. You should inflate the child layout like this:
LinearLayout childItem = (LinearLayout) inflater.inflate(
R.layout.aaaaaaaaaaaa, featured_listlayout_horizontallayout, false);
Also, I would just use the code below(used in the onCreate method) to find out the visible children on the screen(completely visible or partial visible):
featured_listlayout_horizontallayout.post(new Runnable() {
#Override
public void run() {
DisplayMetrics dm = new DisplayMetrics();
getWindowManager().getDefaultDisplay().getMetrics(dm);
// screen width
final float screenWidth = dm.widthPixels;
final int count = featured_listlayout_horizontallayout
.getChildCount();
int realWidth = 0;
int visibleChildren = 0;
for (int i = 0; i < count; i++) {
final View child = featured_listlayout_horizontallayout
.getChildAt(i);
realWidth += child.getWidth();
if (realWidth < screenWidth) {
visibleChildren++;
} else {
visibleChildren++;
break;
}
}
// visibleChildren now has the visible children on the screen
}
});

Fit image into ImageView, keep aspect ratio and then resize ImageView to image dimensions?

How to fit an image of random size to an ImageView?
When:
Initially ImageView dimensions are 250dp * 250dp
The image's larger dimension should be scaled up/down to 250dp
The image should keep its aspect ratio
The ImageView dimensions should match scaled image's dimensions after scaling
E.g. for an image of 100*150, the image and the ImageView should be 166*250.
E.g. for an image of 150*100, the image and the ImageView should be 250*166.
If I set the bounds as
<ImageView
android:id="#+id/picture"
android:layout_width="250dp"
android:layout_height="250dp"
android:layout_gravity="center_horizontal"
android:layout_marginTop="20dp"
android:adjustViewBounds="true" />
images fit properly in the ImageView, but the ImageView is always 250dp * 250dp.
May not be answer for this specific question, but if someone is, like me, searching for answer how to fit image in ImageView with bounded size (for example, maxWidth) while preserving Aspect Ratio and then get rid of excessive space occupied by ImageView, then the simplest solution is to use the following properties in XML:
android:scaleType="centerInside"
android:adjustViewBounds="true"
(The answer was heavily modified after clarifications to the original question)
After clarifications:
This cannot be done in xml only. It is not possible to scale both the image and the ImageView so that image's one dimension would always be 250dp and the ImageView would have the same dimensions as the image.
This code scales Drawable of an ImageView to stay in a square like 250dp x 250dp with one dimension exactly 250dp and keeping the aspect ratio. Then the ImageView is resized to match the dimensions of the scaled image. The code is used in an activity. I tested it via button click handler.
Enjoy. :)
private void scaleImage(ImageView view) throws NoSuchElementException {
// Get bitmap from the the ImageView.
Bitmap bitmap = null;
try {
Drawable drawing = view.getDrawable();
bitmap = ((BitmapDrawable) drawing).getBitmap();
} catch (NullPointerException e) {
throw new NoSuchElementException("No drawable on given view");
} catch (ClassCastException e) {
// Check bitmap is Ion drawable
bitmap = Ion.with(view).getBitmap();
}
// Get current dimensions AND the desired bounding box
int width = 0;
try {
width = bitmap.getWidth();
} catch (NullPointerException e) {
throw new NoSuchElementException("Can't find bitmap on given view/drawable");
}
int height = bitmap.getHeight();
int bounding = dpToPx(250);
Log.i("Test", "original width = " + Integer.toString(width));
Log.i("Test", "original height = " + Integer.toString(height));
Log.i("Test", "bounding = " + Integer.toString(bounding));
// Determine how much to scale: the dimension requiring less scaling is
// closer to the its side. This way the image always stays inside your
// bounding box AND either x/y axis touches it.
float xScale = ((float) bounding) / width;
float yScale = ((float) bounding) / height;
float scale = (xScale <= yScale) ? xScale : yScale;
Log.i("Test", "xScale = " + Float.toString(xScale));
Log.i("Test", "yScale = " + Float.toString(yScale));
Log.i("Test", "scale = " + Float.toString(scale));
// Create a matrix for the scaling and add the scaling data
Matrix matrix = new Matrix();
matrix.postScale(scale, scale);
// Create a new bitmap and convert it to a format understood by the ImageView
Bitmap scaledBitmap = Bitmap.createBitmap(bitmap, 0, 0, width, height, matrix, true);
width = scaledBitmap.getWidth(); // re-use
height = scaledBitmap.getHeight(); // re-use
BitmapDrawable result = new BitmapDrawable(scaledBitmap);
Log.i("Test", "scaled width = " + Integer.toString(width));
Log.i("Test", "scaled height = " + Integer.toString(height));
// Apply the scaled bitmap
view.setImageDrawable(result);
// Now change ImageView's dimensions to match the scaled image
LinearLayout.LayoutParams params = (LinearLayout.LayoutParams) view.getLayoutParams();
params.width = width;
params.height = height;
view.setLayoutParams(params);
Log.i("Test", "done");
}
private int dpToPx(int dp) {
float density = getApplicationContext().getResources().getDisplayMetrics().density;
return Math.round((float)dp * density);
}
The xml code for the ImageView:
<ImageView a:id="#+id/image_box"
a:background="#ff0000"
a:src="#drawable/star"
a:layout_width="wrap_content"
a:layout_height="wrap_content"
a:layout_marginTop="20dp"
a:layout_gravity="center_horizontal"/>
Thanks to this discussion for the scaling code:
http://www.anddev.org/resize_and_rotate_image_-_example-t621.html
UPDATE 7th, November 2012:
Added null pointer check as suggested in comments
<ImageView android:layout_width="match_parent"
android:layout_height="wrap_content"
android:scaleType="centerCrop"
android:adjustViewBounds="true"/>
The Below code make the bitmap perfectly with same size of the imageview. Get the bitmap image height and width and then calculate the new height and width with the help of imageview's parameters. That give you required image with best aspect ratio.
int currentBitmapWidth = bitMap.getWidth();
int currentBitmapHeight = bitMap.getHeight();
int ivWidth = imageView.getWidth();
int ivHeight = imageView.getHeight();
int newWidth = ivWidth;
newHeight = (int) Math.floor((double) currentBitmapHeight *( (double) new_width / (double) currentBitmapWidth));
Bitmap newbitMap = Bitmap.createScaledBitmap(bitMap, newWidth, newHeight, true);
imageView.setImageBitmap(newbitMap)
enjoy.
try adding android:scaleType="fitXY" to your ImageView.
The Best solution that works in most cases is
Here is an example:
<ImageView android:id="#+id/avatar"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:scaleType="fitXY"/>
this can all be done using XML... the other methods seem pretty complicated.
Anyway, you just set the height to what ever you want in dp, then set the width to wrap content or visa versa. Use scaleType fitCenter to adjust the size of the image.
<ImageView
android:layout_height="200dp"
android:layout_width="wrap_content"
android:scaleType="fitCenter"
android:adjustViewBounds="true"
android:src="#mipmap/ic_launcher"
android:layout_below="#+id/title"
android:layout_margin="5dip"
android:id="#+id/imageView1">
After searching for a day, I think this is the easiest solution:
imageView.getLayoutParams().width = 250;
imageView.getLayoutParams().height = 250;
imageView.setAdjustViewBounds(true);
Edited Jarno Argillanders answer:
How to fit Image with your Width and Height:
1) Initialize ImageView and set Image:
iv = (ImageView) findViewById(R.id.iv_image);
iv.setImageBitmap(image);
2) Now resize:
scaleImage(iv);
Edited scaleImage method: (you can replace EXPECTED bounding values)
private void scaleImage(ImageView view) {
Drawable drawing = view.getDrawable();
if (drawing == null) {
return;
}
Bitmap bitmap = ((BitmapDrawable) drawing).getBitmap();
int width = bitmap.getWidth();
int height = bitmap.getHeight();
int xBounding = ((View) view.getParent()).getWidth();//EXPECTED WIDTH
int yBounding = ((View) view.getParent()).getHeight();//EXPECTED HEIGHT
float xScale = ((float) xBounding) / width;
float yScale = ((float) yBounding) / height;
Matrix matrix = new Matrix();
matrix.postScale(xScale, yScale);
Bitmap scaledBitmap = Bitmap.createBitmap(bitmap, 0, 0, width, height, matrix, true);
width = scaledBitmap.getWidth();
height = scaledBitmap.getHeight();
BitmapDrawable result = new BitmapDrawable(context.getResources(), scaledBitmap);
view.setImageDrawable(result);
LinearLayout.LayoutParams params = (LinearLayout.LayoutParams) view.getLayoutParams();
params.width = width;
params.height = height;
view.setLayoutParams(params);
}
And .xml:
<ImageView
android:id="#+id/iv_image"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_horizontal" />
if it's not working for you then replace android:background with android:src
android:src will play the major trick
<ImageView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:adjustViewBounds="true"
android:scaleType="fitCenter"
android:src="#drawable/bg_hc" />
it's working fine like a charm
Use this code:
<ImageView android:id="#+id/avatar"
android:layout_width="fill_parent"
android:layout_height="match_parent"
android:scaleType="fitXY" />
This did it for my case.
<ImageView android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_centerHorizontal="true"
android:scaleType="centerCrop"
android:adjustViewBounds="true" />
I needed to have an ImageView and an Bitmap, so the Bitmap is scaled to ImageView size, and size of the ImageView is the same of the scaled Bitmap :).
I was looking through this post for how to do it, and finally did what I want, not the way described here though.
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="#+id/acpt_frag_root"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#color/imageBackground"
android:orientation="vertical">
<ImageView
android:id="#+id/acpt_image"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:adjustViewBounds="true"
android:layout_margin="#dimen/document_editor_image_margin"
android:background="#color/imageBackground"
android:elevation="#dimen/document_image_elevation" />
and then in onCreateView method
#Nullable
#Override
public View onCreateView(LayoutInflater inflater, #Nullable ViewGroup container, #Nullable Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.fragment_scanner_acpt, null);
progress = view.findViewById(R.id.progress);
imageView = view.findViewById(R.id.acpt_image);
imageView.setImageBitmap( bitmap );
imageView.getViewTreeObserver().addOnGlobalLayoutListener(()->
layoutImageView()
);
return view;
}
and then layoutImageView() code
private void layoutImageView(){
float[] matrixv = new float[ 9 ];
imageView.getImageMatrix().getValues(matrixv);
int w = (int) ( matrixv[Matrix.MSCALE_X] * bitmap.getWidth() );
int h = (int) ( matrixv[Matrix.MSCALE_Y] * bitmap.getHeight() );
imageView.setMaxHeight(h);
imageView.setMaxWidth(w);
}
And the result is that image fits inside perfectly, keeping aspect ratio,
and doesn't have extra leftover pixels from ImageView when the Bitmap is inside.
Result
It's important ImageView to have
wrap_content and adjustViewBounds to true,
then setMaxWidth and setMaxHeight will work, this is written in the source code of ImageView,
/*An optional argument to supply a maximum height for this view. Only valid if
* {#link #setAdjustViewBounds(boolean)} has been set to true. To set an image to be a
* maximum of 100 x 100 while preserving the original aspect ratio, do the following: 1) set
* adjustViewBounds to true 2) set maxWidth and maxHeight to 100 3) set the height and width
* layout params to WRAP_CONTENT. */
I needed to get this done in a constraint layout with Picasso, so I munged together some of the above answers and came up with this solution (I already know the aspect ratio of the image I'm loading, so that helps):
Called in my activity code somewhere after setContentView(...)
protected void setBoxshotBackgroundImage() {
ImageView backgroundImageView = (ImageView) findViewById(R.id.background_image_view);
if(backgroundImageView != null) {
DisplayMetrics displayMetrics = new DisplayMetrics();
getWindowManager().getDefaultDisplay().getMetrics(displayMetrics);
int width = displayMetrics.widthPixels;
int height = (int) Math.round(width * ImageLoader.BOXART_HEIGHT_ASPECT_RATIO);
// we adjust the height of this element, as the width is already pinned to the parent in xml
backgroundImageView.getLayoutParams().height = height;
// implement your Picasso loading code here
} else {
// fallback if no element in layout...
}
}
In my XML
<?xml version="1.0" encoding="utf-8"?>
<android.support.constraint.ConstraintLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:layout_editor_absoluteY="0dp"
tools:layout_editor_absoluteX="0dp">
<ImageView
android:id="#+id/background_image_view"
android:layout_width="0dp"
android:layout_height="0dp"
android:scaleType="fitStart"
app:srcCompat="#color/background"
android:adjustViewBounds="true"
tools:layout_editor_absoluteY="0dp"
android:layout_marginTop="0dp"
android:layout_marginBottom="0dp"
android:layout_marginRight="0dp"
android:layout_marginLeft="0dp"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintTop_toTopOf="parent"/>
<!-- other elements of this layout here... -->
</android.support.constraint.ConstraintLayout>
Note the lack of a constraintBottom_toBottomOf attribute. ImageLoader is my own static class for image loading util methods and constants.
I am using a very simple solution. Here my code:
imageView.setLayoutParams(new LinearLayout.LayoutParams(LinearLayout.LayoutParams.MATCH_PARENT,LinearLayout.LayoutParams.MATCH_PARENT));
imageView.setScaleType(ImageView.ScaleType.FIT_XY);
imageView.getLayoutParams().height = imageView.getLayoutParams().width;
imageView.setMinimumHeight(imageView.getLayoutParams().width);
My pictures are added dynamically in a gridview. When you make these settings to the imageview, the picture can be automatically displayed in 1:1 ratio.
Use Simple math to resize the image . either you can resize ImageView or you can resize drawable image than set on ImageView . find the width and height of your bitmap which you want to set on ImageView and call the desired method. suppose your width 500 is greater than height than call method
//250 is the width you want after resize bitmap
Bitmat bmp = BitmapScaler.scaleToFitWidth(bitmap, 250) ;
ImageView image = (ImageView) findViewById(R.id.picture);
image.setImageBitmap(bmp);
You use this class for resize bitmap.
public class BitmapScaler{
// Scale and maintain aspect ratio given a desired width
// BitmapScaler.scaleToFitWidth(bitmap, 100);
public static Bitmap scaleToFitWidth(Bitmap b, int width)
{
float factor = width / (float) b.getWidth();
return Bitmap.createScaledBitmap(b, width, (int) (b.getHeight() * factor), true);
}
// Scale and maintain aspect ratio given a desired height
// BitmapScaler.scaleToFitHeight(bitmap, 100);
public static Bitmap scaleToFitHeight(Bitmap b, int height)
{
float factor = height / (float) b.getHeight();
return Bitmap.createScaledBitmap(b, (int) (b.getWidth() * factor), height, true);
}
}
xml code is
<ImageView
android:id="#+id/picture"
android:layout_width="250dp"
android:layout_height="250dp"
android:layout_gravity="center_horizontal"
android:layout_marginTop="20dp"
android:adjustViewBounds="true"
android:scaleType="fitcenter" />
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" />
Just write it in xml
android:scaleType="centerCrop"
Worked for me
In my case, I found the answer buried in a comment on this question (credit to #vida).
android:scaleType="centerInside"
How about using android:scaleType="centerInside" instead of android:scaleType="centerCrop"? It would also not crop the image but ensure that both width and height are less than or equal the imageview's width and height :) Here's a good visual guide for scaletypes: Android ImageView ScaleType: A Visual Guide
I just use ImageView inside ConstraintLayout and set adjustviewbound in ImageView to true.
<androidx.constraintlayout.widget.ConstraintLayout
android:layout_width="match_parent"
android:layout_height="match_parent">
<ImageView
android:layout_width="match_parent"
android:layout_height="0dp"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintEnd_toEndOf="parent"
android:src="#drawable/myimg"
android:adjustViewBounds="true"
/>
</androidx.constraintlayout.widget.ConstraintLayout>

Scaling ImageView to device width

In my Android App I have a Activity which show images which have following size 244 x 330.
I want to show those images in full device width.
My layout file looks like this:
<?xml version="1.0" encoding="utf-8"?>
<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:orientation="vertical">
<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>
I tried to set the ScaleType of the ImageView but there is no ScalingType which scales the ImageView proportional.
How can I scale the image proportionally to fit the whole screen in landscape mode AND portrait mode?
Basically what I want is something like ScaleType.CENTER_CORP but which also sets the proportional height for the image so I can see all of it and not just a part of the image.
Edit cause I know I'm confusing you with my "weird" questing.
I want to show it to you with a image.
This is what I get at the moment with my layout. I want to fill the whole grey area by scaling the image as big as needed. How can I accomplish that?
When I set the ScaleType to CENTER_CROP I get this
but this is not what I want cause you are not seeing the whole image just a part from the center.
And this is what I want it to be:
I hope this helps you to understand what I'm trying to accomplish.
Anyone knows how to do that?
Edit 2:
It might look weird and little confusing that I'm trying to display a image which is bigger in the height than the screen size but since I'm using a ScrollView in my example layout this should be ok and the user could scroll if he want to see the not displayed area.
Hope this helps to understand what I'm trying to do.
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).

Categories

Resources