Android ImageView scaling conflict - android

I am creating ImageView in code:
ImageView vlogo = new ImageView(v.getContext());
RelativeLayout.LayoutParams vlogoParams = new RelativeLayout.LayoutParams(
RelativeLayout.LayoutParams.WRAP_CONTENT,
RelativeLayout.LayoutParams.WRAP_CONTENT);
vlogoParams.addRule(RelativeLayout.ALIGN_TOP,tv_visitor.getId());
vlogoParams.addRule(RelativeLayout.ALIGN_LEFT, tv_visitor.getId());
vlogoParams.addRule(RelativeLayout.ALIGN_BOTTOM, tv_visitor.getId());
vlogo.setLayoutParams(vlogoParams);
vlogo.setImageResource(R.drawable.star);
rl.addView(vlogo);
The image is "scaled" by aligning it to TOP and BOTTOM of previously created tv_visitor view (that has been added to relative layout). But I asume that it isn't layedout yet(?). .requestLayout just before this code doesn't change a thing.
By doing that I'm setting ImageView's height to the height of tv_visitor view. Which is OK. However the width seems to stay original.
And here comes the problem. The width stays not scaled. The way I do that is making .setAdjustViewBounds(true); not working. How should I proceed then?
As requested in comments I provide more info:
<?xml version="1.0" encoding="utf-8"?>
<ScrollView xmlns:android="http://schemas.android.com/apk/res/android"
android:id="#+id/news_scrollView"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#ff000000"
android:scrollbars="none">
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:id="#+id/fragment_news2">
<View
android:id="#+id/anchor_n"
android:layout_width="0dp"
android:layout_height="0dp"
android:background="#ffbb00"
android:layout_alignParentTop="true"
android:layout_alignParentLeft="true" />
</RelativeLayout>
</ScrollView>
The View is passed as an parameter and layout is gotten by:
RelativeLayout rl = (RelativeLayout) v.findViewById(R.id.fragment_news2);

The problem is due to the scaling of Imageview, since by default imageview is using ImageView.ScaleType.FIT_CENTER. As per the documentation FIT_CENTER performs the following operation:
Compute a scale that will maintain the original src aspect ratio, but
will also ensure that src fits entirely inside dst. At least one axis
(X or Y) will fit exactly. The result is centered inside dst.
Since the Image is resized and centered, you are seeing extra spaces on both left and right side. To avoid that set ScaleType to ImageView.ScaleType.FIT_END which in turn aligns the result to the right will solve the problem.
vlogo.setScaleType(ImageView.ScaleType.FIT_END);

Related

How to put views on top of an ImageView, in relation to the ImageView's content size?

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>

Android ImageView setLayoutParams with width bigger than Screen

I have ImageView in layout xml like this:
<ImageView
android:id="#+id/notePointerImageView"
android:layout_width="700px"
android:layout_height="6px"
android:scaleType="fitXY"
android:src="#drawable/whiteline"
/>
And I dynamically set the width, height, and Margins in onWindowFocusChanged:
RelativeLayout.LayoutParams notePointerLayoutLP = new RelativeLayout.LayoutParams(263, 2);
notePointerLayoutLP.setMargins(0, 150, 14, 0);
notePointerImageView.setLayoutParams(notePointerLayoutLP);
notePointerImageView.requestLayout();
Since the screen width is only 240x301, the imageView has its left part off screen. But looks like that part of imageView is eliminated and the image is resized inside the screen (I used fitXY), and leaving the ImageView size to be 226x2. (226 + 14 == 240, which is the screen width)
Since I have to animate the ImageView later, I cannot accept ImageView to be clipped and resized. I really need a negative left margin. Could somebody tell me how can I do this? Or is it only a simulator problem?
To force big image to fit inside screen or some size, you can use FrameLayout as:
<FrameLayout
android:id="#+id/fm_image"
android:layout_width="match_parent"
android:layout_height="wrap_content"
... ...
>
<ImageView
android:id="#+id/myImage"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:adjustViewBounds="true"
android:layout_gravity="center"
android:gravity="center"
android:src="#drawable/my_image"/>
</FrameLayout>
for fit specific size, you just set the layout size for FrameLayout.
Hope this help!

Resize parent to match its child

I have a complex xml layout with part of it being:
...
<FrameLayout
android:id="#+id/parent"
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_gravity="center_horizontal"
android:layout_marginLeft="30dp"
android:layout_marginRight="30dp"
android:layout_weight="1" >
<ImageView
android:id="#+id/flexible_imageview"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:adjustViewBounds="true" />
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_gravity="bottom"
android:background="#drawable/gradient"
android:orientation="vertical"
android:paddingBottom="16dp"
android:paddingLeft="16dp"
android:paddingTop="8dp" >
<TextView
android:id="#+id/textView1"
android:layout_width="wrap_content"
android:layout_height="wrap_content" />
<TextView
android:id="#+id/textView2"
android:layout_width="wrap_content"
android:layout_height="wrap_content" />
</LinearLayout>
</FrameLayout>
...
The height of the FrameLayout #+id/parent must be determined at runtime because it is displayed above many other views, and they must be shown in the layout. This way the FrameLayout fills the remaining space perfectly (using height="0dp" and weight="1" properties).
The ImageView #+id/flexible_imageview receives an image from the network, and it always shows with the correct aspect ratio. This part is already ok as well. This View is the largest and should determine the size of the FrameLayout #+id/parent.
The problem is that when the image is drawn, the width of the FrameLayout #+id/parent is not adjusted to wrap and be the ImageView #+id/flexible_imageview as it should be.
Any help is appreciated.
-- update --
I've updated the layout to clarify some of the missing parts, and to add the reasoning behind all of it.
What I want is to have an Image (ImageView #+id/flexible_imageview) with unknown dimensions to have, on top of it, a gradient and some text on top of the gradient. I can't set the FrameLayout #+id/parent dimensions to both wrap_content because there is more Views after this Image that must be shown. If there's not enough space in the layout, the Image (ImageView #+id/flexible_imageview) is reduced until it all fits in the layout, but it should maintain its aspect ratio, and the gradient/texts on top of it.
The #drawable/gradient is just:
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android" >
<gradient
android:angle="270"
android:endColor="#aa000000"
android:startColor="#00000000" />
</shape>
-- update 2 --
I added two images below to demonstrate what's happening, and what should happen:
Bug:
Correct:
If would help if you explained more about what you are trying to accomplish in your layout (not the layout itself but what should the user see on the screen and what are the other elements in the layout).
A FrameLayout with multiple children is usually a "code smell". Usually, FrameLayouts should have only one child element. So this makes me wonder whether there is something wrong with your design.
-- Edit --
If I understand correctly, you are trying the framelayout to wrap the content of the image but at the same time match the space left from the other layout views before/after the frame layout.
What is the parent view/layout of the frame layout?
I see a couple of problems with this design or your explanation:
You have framelayout width set to match parent, but you want to wrap the content of the image.
You want the imageView to be reduced but you are not taking into account the text views in the linear layout. You have them set to wrap content. So when the fame layout is small, you will not see all the textviews. (Unless you are resizing them as well somehow).
Sorry if this isn't helpful enough but it's difficult to understand what you are trying to accomplish with this layout. A sample use-case would help in providing you a better recommendation.
When a dimension (width / height) is MeasureSpec.EXACTLY adjustViewBounds will not effect it.
In your case, having android:width="match_parent" ensures that the image view is the size of the parent, regardless of adjustViewBounds.
It works to begin with because the height is wrap_content - the height is adjusted when the image is scaled to fill the width.
When you override the height to fit everything on the screen (this may not be a great idea to begin with), the width is still matching the parent and doesn't get adjusted. However, because the scale type is ScaleType.FIT_CENTER the image is scaled and positioned so that the entirety of it fits in the bounds of the ImageView (and centred.. hence the name).
If you turn on the debug option for drawing layout bounds, or look at your app using hierarchyviewer, you'll see that the image view is still matching the width of its parent.
There are a couple of ways you could do what you want.
Since you're already manually calculating the height, setting the width shouldn't be that hard.
Drawable drawable = imageView.getDrawable();
if (drawable != null && drawable.getIntrinsicWidth() > 0 && drawable.getIntrinsicHeight() > 0) {
int height = // however you calculate it
int width = height / (getDrawable().getIntrinsicHeight() / getDrawable().getIntrinsicWidth());
}
You might also get away with
<ImageView
android:id="#+id/flexible_imageview"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:adjustViewBounds="true"
android:minWidth="9999dp" />
Even if this works, you probably wouldn't be able to use it in a horizontal LinearLayout using weights any more (for example, if you wanted a landscape variant of the layout), or a number of other scenarios.

align view to a scaled ImageView

i have this problem frequently, and I refuse to believe that it can't be solved without creating a custom layout:
How do you align a view with an ImageView that get scaled to match it's parent bounds but keeps the aspect ratio ( scale type is anything but fitXY ). I was under the assumption that f you set adjustViewBounds to true, the view bounds get adjusted to match the actual size of the image ("Set this to true if you want the ImageView to adjust its bounds to preserve the aspect ratio of its drawable."). But that is not the case. And it doesn't make and difference if the image has to get scaled up or down to fit its bounds.
Take a look at this layout:
<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"
android:paddingBottom="#dimen/activity_vertical_margin"
android:paddingLeft="#dimen/activity_horizontal_margin"
android:paddingRight="#dimen/activity_horizontal_margin"
android:paddingTop="#dimen/activity_vertical_margin"
>
<ImageView
android:id="#+id/imageView1"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:adjustViewBounds="true"
android:scaleType="fitCenter"
android:src="#drawable/square" />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignRight="#+id/imageView1"
android:layout_alignTop="#+id/imageView1"
android:text="#string/hello_world" />
</RelativeLayout>
This layout looks like this:
As you can see the bounds do not get adjusted and the TextView is aligned to the incorrect bounds. I created a custom Layout to creates the proper bounds, but maybe I'm missing something and it should be possible using the standard layout features...
EDIT: to clarify: i'm looking for a way to align the TextView with the actual image. that is with the red square in the given example.
Ok, so it's been three years and you probably figured this out long ago. But you were halfway there when you specified adjustviewBounds=true. You just needed to change the ImageView layout width and height to wrap_content at the same time.
Your TextView IS aligning to your ImageView just as you requested. If you were to give your ImageView a background color you would see that it occupies the same area as your TextView. It's just that the actual image is centered within the view as you requested.
And you can continue to use scaleType=fitCenter or centerInside depending upon what you want. Neither will crop or stretch the image and your TextView will remain aligned.
What if you use - android:scaleType="centerCrop" on the ImageView?
The image will be cropped to cover the entire layout, but the aspect ratio will be maintained.

Margin/Padding Shrinks ImageView

I recently tried to position an imageview's x and y coordinates with no luck, it seems there is no way to do it in Gingerbread. I then decided to try out paddings and margins, but when I set them, it shrinks my imageview. I set a left padding of 250dp and image view became tiny. The layout_height and width are set to wrap_content. I'm not sure what's going on. Does anyone know why setting a padding/margin would shrink an imageview?
You're confusing margin and padding. Margin is the area outside of your view, while padding affects the content inside your margin.
If you set padding, then it is going to affect your available content area, and assuming you have a ScaleType set, it's going to shrink your image down to fit the available space.
Now, you say you've tried margins, but margins will do exactly what you're asking.
For example, if you wanted an ImageView placed 10dp from the top-left corner, you can do something like this:
<?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:id="#+id/my_image_view"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentTop="true"
android:layout_alignParentLeft="true"
android:layout_marginTop="10dp"
android:layout_marginLeft="10dp"
android:src="#drawable/my_image_id"
/>
</RelativeLayout>
Keep in mind that this places it 10dp with respect to the parent boundaries. If your parent layout also has padding, then that will affect your content placement.
if by shrink you mean the picture's ratio is messed then you should use
android:scaleType="centerInside"
this will prevent the ratio from changing

Categories

Resources