Why my ImageView would not change width in Android? - android

I'm developing an Android app with avatar (the image icon), the ImageView is inside an RelativeLayout like this
<ImageView
android:id="#+id/indicators"
android:layout_width="#dimen/conversation_avatar_size"
android:layout_height="#dimen/conversation_list_left_indicator_height"
android:layout_below="#id/contact_image"
android:layout_alignWithParentIfMissing="true"
android:layout_marginEnd="#dimen/smaller_def_margin"
android:layout_marginTop="#dimen/smaller_def_margin"
android:scaleType="fitCenter"
tools:src="#drawable/ic_reply"/>
However, I cannot change the width of this ImageView when I make the contact_image invisible because indicator takes less space. The code is like below
indicators.getLayoutParams().width = width;
indicatorsWidth = indicators.getWidth();
indicators.requestLayout();
After indicators.requestLayout(); the width of the indicator still keeps the old one not changed to width. I'm wondering why this can happen? I also tried indicators.setLayoutParams(layoutParams); but still doesn't work.
I did find some interesting, even though indicators.getWidth() is still the old value, indicators.getLayoutParams().width is the new width now, and ImageView size doesn't change at all.
Update : I found what view.getWidth() is, and then I used indicators.setLeft() and indicators.setRight(), this time indicators.getWidth() is also the new width, however, the size still doesn't change, I checked it and found that indicators.getMeasuredWidth() is still the old value, any idea?

Your issue may be android:scaleType="fitCenter" if the height of the ImageView is the constraining factor. The view will be resized to fit the height and maintain the aspect ratio by adjusting the width. See this.
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.
Here is a small app to play with this concept. You will see that even though the width is change, the height is not with android:scaleType="fitCenter". If you change it to android:scaleType="fitXY", you will see a change. This may not be your issue exactly, but you can use this code which is an MCVE to test out some ideas.
MainActivity.java
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
final ImageView indicators = findViewById(R.id.indicators);
indicators.postDelayed(new Runnable() {
#Override
public void run() {
indicators.getLayoutParams().width = 500;
indicators.requestLayout();
}
}, 2000);
}
}
activity_main.xml
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:id="#+id/parent"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal">
<ImageView
android:id="#+id/indicators"
android:layout_width="100px"
android:layout_height="100px"
android:layout_alignWithParentIfMissing="true"
android:scaleType="fitCenter"
android:src="#mipmap/ic_launcher"/>
</RelativeLayout>

When modifying LayoutParams, you have to reassign the object back to the view or there will be no effect.
ViewGroup.LayoutParams params = myView.getLayoutParams();
params.width = newWidth;
myView.setLayoutParams(params);
This last line is what actually changes the width of the view.

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 scaling conflict

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);

Dimensions of usable space in window (action bar and margin excluded)

Disclaimer: I rewrote most of this question, including its title, because I partially figured it out.
I'd like to maximize the size of the button on all screen sizes, because it looks silly when it is to small. It should look similar to this:
(Sadly, I cannot include a picture, because my reputation is too low.)
But if I turn the orientation of the device, for example, the button matches it's parents width, becoming ugly proportioned.
(Sadly, I cannot include a picture, because my reputation is too low.)
I now have figured out how to get the dimensions of its parent (the LinearLayout) and how to set the button's size. I used the following code:
window is the ID of the LinearLayout containing (only) the button.
this code is located in the onCreate()-method of the MainActivity.
// Adapt button's size to smaller dimension:
final View window = findViewById(R.id.window);
window.getViewTreeObserver().addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {
#Override
public void onGlobalLayout() {
int width = window.getMeasuredWidth();
int height = window.getMeasuredHeight();
int smallerSize;
if (width < height) {
smallerSize = width;
} else {
smallerSize = height;
}
View button = findViewById(R.id.fartButton);
button.setLayoutParams(new LinearLayout.LayoutParams(smallerSize, smallerSize));
window.getViewTreeObserver().removeOnGlobalLayoutListener(this);
}
});
The problem with this approach is, that it doesn't seem to account for padding. The button get's cut off a little bit on the smaller side (in portrait mode its width, in landscape mode its height).
Interestingly, the image inside the button fits the window perfectly. If for example the height gets cut off a bit, the image still is visible in its full height (only some "extra" parts of the button get cut off, like a little border and shadow).
Is there a way to get the maximal size of the button, which would be the size of the window, but without action bar and minus padding, to prevent any part of the button to get cut off?
Your example above "should look similar to this:" does not seem to have loaded, illustration would help...
But you can manage screen proportions pretty well using android:layout_weight
I'm not sure I'm envisioning your exact needs, but you might try something like this:
<LinearLayout
android:orientation="horizontal"
android:layout_width="match_parent"
android:layout_height="match_parent" >
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_weight="X"
android:text=" "
/>
<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_weight="1"
android:text="button"
/>
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_weight="X"
android:text=" "
/>
</LinearLayout>
where different values for X would control the horizontal aspect ratio for your button in a view.
I just figured it out. Was much easier than I thought. Thanks to everyone who answered, though. It helped me a lot on the way!
The padding that is applied to the window can easily be accesed through the getPadding...() methods. I just needed to adjust the part where the width and height get saved:
int width = window.getMeasuredWidth() - window.getPaddingLeft() - window.getPaddingRight();
int height = window.getMeasuredHeight() - window.getPaddingTop() - window.getPaddingBottom();
I thought, that even by manually excluding the padding, the highlight when pressing the button would be cut off, because it is a bit bigger than the button itself. But this is not the case and it works perfectly. The button now gets displayed in its whole glory. ;)
You can overload your onMeasure method to always return a square.
Create a class that extends to Button and include this
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
int size = Math.min(getMeasuredWidth(), getMeasuredHeight());
setMeasuredDimension(size, size);
}
Not sure how this will work if you give exact dimensions but it should work if you set width, height to match parent

Dynamic positioning of a Button [Android]

I have a RelativeLayout which holds an ImageView and an ImageButton. The ImageView serves as an container for a background image. Now I'm trying to set the button at a fixed position so that it always appears on the same position on the background image.
Here is the layout file I'm using:
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="#+id/relativeLayout1" android:layout_height="match_parent"
android:layout_width="match_parent" android:gravity="center_horizontal">
<ImageView android:src="#drawable/bg_1" android:id="#+id/imgView"
android:adjustViewBounds="true" android:layout_height="match_parent"
android:layout_width="match_parent" />
<ImageButton android:layout_width="120dp"
android:background="#drawable/button_1" android:layout_height="30dp"
android:id="#+id/imgButton" android:layout_marginLeft="100dp"
android:layout_marginTop="170dp" />
</RelativeLayout>
As you can see I've tried positioning the button with it's left-/top-margin using dp as unit, but this doesn't work. Since the background image is beeing scaled down/up, the position would have to be dynamic in some kind of way.
I understand that absolute positioning, with pixel-values for x-/y-position, is something that won't work on Android, like it is explained here. I still need to solve this and am not sure how.
Would I have to calculate the values for left-/top-margin (not sure how that would be) and then set them with something like this?
final float density = getResources().getDisplayMetrics().density;
int width = (int)((float)120 * density);
int height = (int)((float)120 * density);
RelativeLayout.LayoutParams rlp = new RelativeLayout.LayoutParams(width, height);
rlp.leftMargin = newMargin;
rlp.topMargin = newTopMargin;
ImageButton imgButton = (ImageButton) findViewById(R.id.imgButton);
imgButton.setLayoutParams(rlp);
Hope I didn't forget something ...
//EDIT:
I was thinking, the reason for the issue might be, that the scaled image has different "borders", depending on the screen size.
With an image at a 1:1.6 ratio on a HVGA screen I have black bars on the left and right, whereas on a WVGA screen the bars are on the left. Considering I'm using the default scaling. I will look into it and post again, if necessaray...
Why scaling happens? Because of different dpi on different devices? Do you have different drawabled for different dpi settings? If it isn't just dpi issue and you want to scale that background image freely then you can't do the job using standard layouts. You should implement a custom one.

How to create a view that is bigger than the screen?

Is it possible to create a view that is bigger than the screen?
I need a view that has a bigger width then the screen of the device. I use this view in a rotation animation. During the rotation the parts that were not on the screen before animating the view will become visible.
Is there a way to achieve this effect with the android framework?
Update
I tried to set my parent layout much bigger then the screen and it is working. This will make somethings a little bit uncomfortable but it could work. The next problem now is that my layout still starts at the left side of the screen. I can't think of a method to make the layout to expand itself to the left and the right of the screen.
Ok I got an answer. It is not very nice because it uses a deprecated View class but it works at least on my current testing screen resolution other resolutions are tested tomorrow.
I wrapped the view that I wanted to expand beyond the screen in an absolute layout like this:
<AbsoluteLayout
android:layout_width="wrap_content"
android:layout_height="fill_parent"
android:layout_alignParentBottom="true">
<ImageView
android:id="#+id/content"
android:layout_width="600dip"
android:layout_height="420dip"
android:scaleType="centerCrop"
android:layout_x="-200dip"
android:layout_y="60dip"
android:src="#color/testcolor" />
</AbsoluteLayout>
The -200 x coordinate makes the view stick 200dip out of the left side of the screen. If I'm animating the view those parts that are outside the screen will gradually become visible.
E.g. setting negative bottom margin together with setting extra large layout_height (large enough for you) solved the similar issue as for me.
Works fine at least using API 11+ animations/rotations.
Could look like:
android:layout_marginBottom="-1000dp"
android:layout_height="1000dp"
In case anyone still comes up on this page. The key is your root layout, it will only work with a FrameLayout (or the deprecated absolutelayout). Then you have two options to make your child view bigger.
through xml, this is quick and easy but you don't know the actual screen width & height in advance so your off with setting a ridiculously high value for layout_width & layout_height to cover all screens.
Calculate the screen size programatically and make the view's width/height proportional bigger to this..
Also be aware that your bigger view still starts in the top left corner of the screen so to account this you will have to give a negative top & left margin that's half of what you are adding to the view's width/height
FrameLayout.LayoutParams params = (FrameLayout.LayoutParams) viewToMakeBigger.getLayoutParams();
int marginLeft = (int) (viewToMakeBigger.getWidth()*0.1);
int marginTop = (int) (viewToMakeBigger.getHeight()*0.1);
params.width = (int) (viewToMakeBigger.getWidth()*1.2);
params.height = (int) (viewToMakeBigger.getHeight()*1.2);
params.leftMargin = -marginLeft;
params.topMargin = -marginTop;
viewToMakeBigger.setLayoutParams(params);
HorizontalScrollView:
http://developer.android.com/reference/android/widget/HorizontalScrollView.html
Layout container for a view hierarchy that can be scrolled by the user, allowing it to be larger than the physical display.
The simple axml below creates an ImageView that is 400dp wider than the screen (even though the layout_width is set to equal the parent's width) using a negative left and right margin of 200dp.
The ImageView is situated 250dp above the top of the screen using a negative top margin, with 450dp of 700dp vertical pixels visible on the screen.
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent">
<ImageView
android:background="#FFFF0000"
android:layout_height="700dp"
android:layout_marginLeft="-200dp"
android:layout_marginRight="-200dp"
android:layout_marginTop="-250dp"
android:layout_width="match_parent" />
</RelativeLayout>
You can override the views in the onMeasure method. This will set your View dimensions to 1000x1000 px.
#Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
setMeasuredDimension(1000, 1000);
}
Is it possible to create a view that is bigger than the screen?
Why not, you can define the layout_width and layout_height in px(or dip) as you want:
android:layout_width="10000px"
android:layout_height="20000px"
You need to change the size of the window, by getWindow().setLayout. This will increase the size for your window. Since the root layout can be as big as its parent you can then increase the size of the view you want to be bigger than the screen size. It works for me let me know
You can use ViewSwitcher to handle that. Used with Animation and a OnGestureListener looks pretty good.
You can do it programmatically:
FrameLayout.LayoutParams rootViewParams = (FrameLayout.LayoutParams) rootView.getLayoutParams();
rootViewParams.height=displayMetrics.heightPixels+(int)dpToPixels(60);
rootViewParams.width=displayMetrics.widthPixels+(int)dpToPixels(60);
rootView.setLayoutParams(rootViewParams);
rootView.setX(rootView.getX() - dpToPixels(30));
rootView.setY(rootView.getY() - dpToPixels(30));
MUST BE ONLY IN
"public void onWindowFocusChanged(boolean hasFocus)" method.
and
rootView = (RelativeLayout) findViewById(R.id.rootLayout);
Inside "protected void onCreate(Bundle savedInstanceState)" method.
Where yout .xml file is like this:
<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:id="#+id/rootLayout"
tools:context="com.example.Activity">
<RelativeLayout
android:layout_width="match_parent"
android:layout_centerHorizontal="true"
android:layout_margin="30dp"
android:layout_centerVertical="true"
android:layout_height="match_parent">
// Bla bla bla
</RelativeLayout>
and:
public float dpToPixels(float dp) {
return TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, dp, context.getResources().getDisplayMetrics());
}

Categories

Resources