I want to have an ImageView with width=fill_parent, and the height should be whatever the width is. I'm not sure if there's a way to specify that in xml, is the only option to create my own ImageView-derived class?:
public class MyImageView extends ImageView {
// Just return whatever the current width is?
private int measureHeight(int measureSpec) {
return getWidth();
}
}
Is this the way to go, any other options? (I'm not sure if the above is even correct, not sure if the width measurement even takes place before the height measurement for example)
Thanks
You can get the width with the method
imageView.getMeasuredWidth();
So, you can set it's height
imageView.setLayoutParams(new LayoutParams(imageView.getMeasuredWidth(), imageView.getMeasuredWidth()));
Make layout height equal to the width:
The problem with digulino's answer (in my case at least) is that if you want to change the dimensions in the start, getMeasuredWidth() will return 0 because the views haven't been drawn yet.
You can still do it by using a Runnable() thread like this:
FrameLayout frame = (FrameLayout)findViewById(R.id.myFrame);
frame.post(new Runnable() {
#Override
public void run() {
RelativeLayout.LayoutParams lparams;
lparams = (RelativeLayout.LayoutParams) frame.getLayoutParams();
lparams.height = frame.getWidth();
frame.setLayoutParams(lparams);
frame.postInvalidate();
}
});
Important Note:
This example assumes your view is a FrameLayout inside a RelativeLayout. Change it accordingly for other layouts.
Related
I have made class called ProgressButton that extended RelativeLayout.Now in main xml i added this class:
<com.tazik.progressbutton.ProgressButton
android:id="#+id/pb_button"
android:layout_width="200dp"
android:layout_height="wrap_content"/>
As you can see i added android:layout_width="200dp", now in ProgressButton class i want to get this size to create a button with this size:
public class ProgressButton extends RelativeLayout {
private AppCompatButton button;
public ProgressButton(Context context) {
super(context);
initView();
}
private void initView() {
initButton();
}
private void initButton() {
button = new AppCompatButton(getContext());
LayoutParams button_params = new LayoutParams(????, ViewGroup.LayoutParams.WRAP_CONTENT);
button_params.addRule(RelativeLayout.CENTER_IN_PARENT,RelativeLayout.TRUE);
button.setLayoutParams(button_params);
button.setText("click");
addView(button);
}
I want to create button exactly to size of relativeLayout, so how can i get layout_width in my custom view to set button_params width?
now in ProgressButton class i want to get this size to create a button with this size
As #MikeM. suggested in a comment. It could be as easy as giving that child view a width of MATCH_PARENT. See below...
LayoutParams button_params = new LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT);
With that in place you don't need to worry about the actual size because MATCH_PARENT will stretch your child view to occupy the whole parent's width...obviosuly respecting margins and paddings.
However, if you do need to know the parent's width, you should query that in onMeasure. I strongly suggest you to stay away from onMeasure whenever possible because it is a bit complex and it might take a lot of your development time.
Either way, in onMeasure you can know what measurements the parent view wants to give to its child views, this is based on the space available to render inside the parent and the layout params specified...
#Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
int widthSpecMode = MeasureSpec.getMode(widthMeasureSpec);
int childWidth = 0;
if(widthSpecMode == MeasureSpec.AT_MOST){
//The parent doesn't want the child to exceed "childWidth", it doesn't care if it smaller than that, just not bigger/wider
childWidth = MeasureSpec.getSize(widthMeasureSpec);
}
else if(widthSpecMode == MeasureSpec.EXACTLY){
//The parent wants the child to be exactly "childWidth"
childWidth = MeasureSpec.getSize(widthMeasureSpec);
}
else {
//The parent doesn't know yet what its children's width will be, probably
//because it's still taking measurements
}
//IMPORTANT!!! set your desired measurements (width and height) or call the base class's onMeasure method. Do one or the other, NOT BOTH
setMeasuredDimension(dimens, dimens);
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
}
Add a few Log.d calls inside onMeasure for a better understanding of what's happening. Be aware that this method will be called multiple times.
Again, this is an unnecessary overkill for your case scenario. Setting MATCH_PARENT to the button should produce the results you want
I make some custom view, and now im stuck with one specific issue.
Now ill try to explain: in my case the view hierarchy is
<view extends linear layout>
<child-view extends relative layout>
<some content>
<relative-layout>
<progressbar> (align text view right, match parent)
<textview> (align parent right, wrap content) <- there's i have to make some changes
<relative-layout>
<child-view>
<...>
<view>
the child items are added according to the data coming from the server.
I want to make all textviews with the same width - width of textview which content length is max. How can I implement this? I tried to calculate width in onMeasure callback, and then set width to another views, but getMeasuredWidth() and getWidth() returns 0 every time. I Heard something about ViewTreeObserver, but i can not understand how to use it right. Thanks in advance!
Try this,
int maxWidth = 0;
....
tv1.getViewTreeObserver().addOnGlobalLayoutListener(new OnGlobalLayoutListener() {
#Override
public void onGlobalLayout() {
int width = layout.getMeasuredWidth();
if(width > maxWidth){
maxWidth = width;
// update all textView width with max width.
}
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.JELLY_BEAN) {
this.layout.getViewTreeObserver().removeGlobalOnLayoutListener(this);
} else {
this.layout.getViewTreeObserver().removeOnGlobalLayoutListener(this);
}
}
});
same code for tv2,tv3 and tv4. it will work.
I have a LinearLayout containing a TextView. The initial height of LinearLayout is set to 20px where the content of TextView overflows its bounds. I want to animate LinearLayout to expand to wrap content (its Children height). How can I determine the final size of LinearLayout before expanding?
Currently I set Height of View to wrap_content for a moment and after measuring the final height reset the height to 20 again! obviously this cause an unwanted blink before animation and should be replaced by a better solution.
//I hate these two lines
view.getLayoutParams().height=ViewGroup.LayoutParams.WRAP_CONTENT;
view.requestLayout();
//End of hate!
view.post(new Runnable() {
#Override
public void run() {
int targetHeight = view.getMeasuredHeight();
view.getLayoutParams().height=20;
view.requestLayout();
}
});
There is a .measure() method for this:
view.measure(LayoutParams.MATCH_PARENT, LayoutParams.WRAP_CONTENT);
int targetHeight = view.getMeasuredHeight();
I have an ImageView which has layout_width of fill_parent. I want to get the width of this ImageView in order to calculate the size of the thumbnail. The problem is that imageView.getWidth() and imageView.getHeight() both return 0 because the layout hasn't been sat yet.
My question is, does the ImageView has some kind of SizeChanged event or something of the kind? How do I react as soon as the ImageView width has been established?
Update:
I solved my problem this way. As I actually only needed the width of the ImageView which is set to fill_parent, what I actually needed was the device window size:
DisplayMetrics metrics = new DisplayMetrics();
getWindowManager().getDefaultDisplay().getMetrics(metrics);
int targetW = metrics.widthPixels;
You can hook into a number of View tree events using a ViewTreeObserver. Specifically, either an OnGlobalLayoutListener or an OnPreDrawListener should work for you depending on what you are doing with the size.
Here's an example of using a ViewTreeObserverto get a View's width once everything has been laid out:
final ImageView myImageView = (ImageView) findViewById(R.id.image);
final ViewTreeObserver observer = myImageView.getViewTreeObserver();
observer.addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {
#Override
public void onGlobalLayout() {
int height = myImageView.getHeight();
// Do something with the height
// Remove the layout listener so we don't waste time on future passes
observer.removeOnGlobalLayoutListener(this);
}
});
According to this post's answer:
ImageView.getWidth() returns 0
You will need to call it from the following function:
public void onWindowFocusChanged(boolean hasFocus)
This is because the window has not yet been attached and as you have noticed your imageview will have no dimensions yet.
I have the a LinearLayout with width set in xml as fill_parent , now i need its width at runtime programatically. So i did this:
LinearLayout layoutGet=(LinearLayout) findViewById(R.id.GameField1);
LayoutParams layParamsGet= layoutGet.getLayoutParams();
int width=layParamsGet.width;
But width value on debugging was found to be -1, anybody with idea why can't i get the exact width at runtime for LinearLayout with fill_parent set in layout xml.
I got a simple approach working.
myLayout = (RelativeLayout) findViewById(R.id.my_layout);
myLayout.post(new Runnable()
{
#Override
public void run()
{
Log.i("TEST", "Layout width : "+ myLayout.getWidth());
}
});
Jens Vossnack's approach mentioned below works fine. However, I found that the onGlobalLayout() method of GlobalLayoutListener is called repeatedly, which may not be appropriate in certain cases.
You can try to listen to the globalLayout event, and get the width in there. You probably get the -1 because you are trying to get the width before the views are layed-out.
vto.addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {
#Override
public void onGlobalLayout() {
//Do it here
LinearLayout layoutGet=(LinearLayout) findViewById(R.id.GameField1);
LayoutParams layParamsGet= layoutGet.getLayoutParams();
int width=layParamsGet.width;
removeOnGlobalLayoutListener(layoutGet, this); // Assuming layoutGet is the View which you got the ViewTreeObserver from
}
});
#SuppressLint("NewApi")
public static void removeOnGlobalLayoutListener(View v, ViewTreeObserver.OnGlobalLayoutListener listener){
if (Build.VERSION.SDK_INT < 16) v.getViewTreeObserver().removeGlobalOnLayoutListener(listener);
else v.getViewTreeObserver().removeOnGlobalLayoutListener(listener);
}
(vto is the view you want to get the width of)
If you look at the value for FILL_PARENT (you should be using MATCH_PARENT since FILL_PARENT is now deprecated) you will notice the value for it is -1. LayoutParams are simply attributes for how your view should look. Once the view is inflated and looks the way the params specify, the view does not go back and change those Params to reflect the actual values of the view (width/height/etc).
If you wanted to get the actual width of your view you would have to call getWidth() on your view once the layout has been inflated and displayed. Calling getWidth() before your layout has been displayed will result in 0.
LinearLayout layoutGet=(LinearLayout) findViewById(R.id.GameField1);
int width = layoutGet.getWidth();
First of all, you should use match_parent instead of fill_parent (deprecated).
When you do int width=layParamsGet.width;, you take the right result which is -1 corresponding at fill_parent.
If you wan't to get the real width, you need to wait onMesure() call and use
LinearLayout layoutGet=(LinearLayout) findViewById(R.id.GameField1);
int width = layoutGet. getMeasuredHeight();
layoutGet.getWidth() should work out