I need to create 4 buttons with equal width in a row. I know how to do that using linear layout and weights, but that's not quite acceptable for me. I have some other views that are related to my 4 buttons, so I'd like to do everything inside relative layout. Is it possible?
How about setting the buttons' width to a standard size?
<Button
android:width="75dp"
... />
Addition
To find the width of the display at runtime:
int width = getWindowManager().getDefaultDisplay().getWidth() / 4;
// Set this width to your buttons
I don't know for sure, but I think that the only way you can do this, without weight tags, is to runtime/programatically setup it. I've done this by setting a constant in a integer.xml, like the following:
<?xml version="1.0" encoding="utf-8"?>
<resources>
<integer name="numberOfButtons">4</integer>
</resources>
And, in your Adapter/Activity class, something like the following:
DisplayMetrics dm = new DisplayMetrics();
// dm holds your structure of resolution
context.getWindowManager().getDefaultDisplay().getMetrics(dm);
int width = dm.getWidth();
btn1.setWidth(width/getInteger(R.integer.numberOfButtons));
btn2.seTwidth(width/getInteger(R.integer.numberOfButtons));
btn3.seTwidth(width/getInteger(R.integer.numberOfButtons));
btn4.seTwidth(width/getInteger(R.integer.numberOfButtons));
Hope this helps you in some way.
choose one of the views that will tell the others to have the same width and height . in order to fetch the size of a view , use something like this:
private static void runJustBeforeBeingDrawn(final View view, final Runnable runnable)
{
final ViewTreeObserver vto = view.getViewTreeObserver();
final OnPreDrawListener preDrawListener = new OnPreDrawListener()
{
#Override
public boolean onPreDraw()
{
Log.d(App.APPLICATION_TAG, CLASS_TAG + "onpredraw");
runnable.run();
final ViewTreeObserver vto = view.getViewTreeObserver();
vto.removeOnPreDrawListener(this);
return true;
}
};
vto.addOnPreDrawListener(preDrawListener);
}
Alternative to runJustBeforeBeingDrawn: https://stackoverflow.com/a/28136027/878126
Related
I have a LinearLayout (vertical) with two child views in it. The 1st one is a ScrollView and the 2nd one is another layout with Visibility.GONE, its size is not fixed (determined by its children).
<LinearLayout vertical>
<ScrollView> ... </ScrollView>
<AnotherLayout visibility=GONE height=wrap_content> ... </AnotherLayout>
</LinearLayout>
At some point of time I want to show AnotherLayout. But, once it pops up, I also want to adjust the scrolling of my ScollView one. For this, I need to know the size of this AnotherLayout.
I'm doing something like that:
int oldHeight = scrollArea.getHeight();
linearLayout.setVisibility(VISIBLE);
int newHeight = scrollArea.getHeight();
But oldHeight and newHeight are still the same.
How can I calculate the new height?
The two dimensions are the same because visibility change took time and the line of code was run before that so it returns the same.
You can use a visibility listener to calculate the dimension after visibility change , You may use that
linearLayout.setTag(linearLayout.getVisibility());
linearLayout.getViewTreeObserver().addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {
#Override
public void onGlobalLayout() {
int newVis = linearLayout.getVisibility();
if((int)linearLayout.getTag() != newVis)
{
linearLayout.setTag(linearLayout.getVisibility());
//visibility has changed
int newHeight = scrollArea.getHeight();
}
}
});
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
I have an Activity with a view hierarchy as follows:
<RelativeLayout>
<LinearLayout>
<GridLayout />
</LinearLayout>
</RelativeLayout>
The top RelativeLayout takes up the full screen while the LinearLayout takes up a subset of the screen. I'm trying to set the size of the children views of the GridLayout in such a way that with n rows and m columns the size of cells is directly related to the n,m values and the width and height of the LinearLayout.
So for example, I'm trying to get the cell width and height as follows:
int linearLayoutWidth = mLinearLayout.getMeasuredWidth();
int linearLayoutHeight = mLinearLayout.getMeasuredHeight();
...
int rows = mGridModel.getRows() + 1;
int columns = mGridModel.getColumns() + 1;
int cellWidth = (int) (linearLayoutWidth / columns);
int cellHeight = (int) (linearLayoutHeight / rows);
Unfortunately, mLinearLayout.getMeasuredWidth() does not return the correct size when the view is created. It always returns the actual device's screen width until the views have been fully laid out - in which case it is too late. I have already given my children cell views the size based on the initially completely incorrect values.
My question is - how do I know when the views have been FULLY laid out. I need to query for their correct or actual measured width/height.
setContentView() creates the views and theoretically lays them out. But they views are not guaranteed to be in their final correct locations/sizes yet.
You can add ViewObserver to any view, in this observer there is a callback method onGlobalLayout, invoked when Layout has been laid;
ViewTreeObserver observer = view.getViewTreeObserver();
observer.addOnGlobalLayoutListener(new OnGlobalLayoutListener() {
#Override
public void onGlobalLayout() {
//in here, place the code that requires you to know the dimensions.
//this will be called as the layout is finished, prior to displaying.
}
}
Extending jeet's answer, you can have your activity implement the listener, which leads to slightly nicer code.
public class MyActivity extends Activity implements ViewTreeObserver.OnGlobalLayoutListener {
#Override
protected void onCreate(Bundle savedInstanceState) {
...
view.getViewTreeObserver().addOnGlobalLayoutListener(this);
}
#Override
public void onGlobalLayout() {
...
}
}
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.