I try to get a FrameLayout's height in onGlobalLayout(), this piece of code is in the onCreate() method:
final FrameLayout layout = (FrameLayout)findViewById(R.id.detail_frame);
ViewTreeObserver vto = layout.getViewTreeObserver();
vto.addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {
#Override
public void onGlobalLayout() {
layout.getViewTreeObserver().removeOnGlobalLayoutListener (this);
ViewGroup.LayoutParams lPF = layout.getLayoutParams();
int gg = layout.getHeight();
int hh = lPF.height;
}
});
The XML file:
<FrameLayout
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:id="#+id/detail_frame">
...
...
</FrameLayout>
but when I was debugging, 'gg' got the right height value, 'hh' got -1. I'm doing this because I want to set the layout's height. How can I get the right value of LayoutParams?
Anyway to know if it's finished laying out?
You already did, onGlobalLayout is called when the view finishes laying out, that's why getHeight return non-zero pixel in height. If it's not drawn yet, getHeight will return 0
How can I get the right value of LayoutParams?
Nothing is wrong here, it's a right value. You get -1 from LayoutParams.height because it's MATCH_PARENT placeholder value, just like WRAP_CONTENT = -2. Android read this layout params value, then calculate the real size in pixel, which will be the value you get when calling getHeight.
I'm doing this because I want to set the layout's height
Just set the height value to the LayoutParams: layout.getLayoutParams().height = 100
I have designed an layout in which LinearLayout has 2 children LinearLayout and FrameLayout and in each child I put different views.
I just wanted to measure height and width of FrameLayout so that I could serve my purpose.
In program I am using
int height,width;
FrameLayout fr=(FrameLayout)findviewbyid(R.id.fr);
height=fr.getHeight();
width=fr.getWidth();
returns value as 0 for both
Even I tried with following code
int height,width;
FrameLayout fr=(FrameLayout)findviewbyid(R.id.fr);
height=fr.getMeasuredHeight();
width=fr.getMeasuredWidth();
returns same value 0
and finally I tried with following code,
int height,width;
FrameLayout fr=(FrameLayout)findviewbyid(R.id.fr);
height=fr.getgetLayoutParams().height();
width=fr.getLayoutParams().width;
returns me -2 and -1
I want the solution to get height and width of any layout programmatically?
The view itself, has it's own life cycle which is basically as follows:
Attached
Measured
Layout
Draw
So, depending on when are you trying to get the width/height you might not see what you expect to see, for example, if you are doing it during onCreate, the view might not even been measured by that time, on the other hand if you do so during onClick method of a button, chances are that by far that view has been attached, measured, layout, and drawn, so, you will see the expected value, you should implement a ViewTreeObserver to make sure you are getting the values at the proper moment.
LinearLayout layout = (LinearLayout)findViewById(R.id.YOUR VIEW ID);
ViewTreeObserver vto = layout.getViewTreeObserver();
vto.addOnGlobalLayoutListener(new OnGlobalLayoutListener() {
#Override
public void onGlobalLayout() {
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.JELLY_BEAN) {
this.layout.getViewTreeObserver().removeGlobalOnLayoutListener(this);
} else {
this.layout.getViewTreeObserver().removeOnGlobalLayoutListener(this);
}
int width = layout.getMeasuredWidth();
int height = layout.getMeasuredHeight();
}
});
As CapDroid say, you are trying to get the size before the view drawn, another possible solution could be to do a Post with a runnable on the View:
mView.post(new Runnable() {
#Override
public void run() {
int width = mView.getWidth();
int height = mView.getHeight();
}
}
Just wanted to add an answer here, since Koltin has some convenience methods to do this, which are a lot less ugly than adding and removing a onGlobalLayoutListener:
view.doOnLayout {
it.measuredWidth
it.measuredHeight
}
You can see more of the convinience methods here.
I think you are getting Height and Width in OnCreate() method that's why you getting always 0 values because at that time your view still not created.
Try to get height and width on some button click or else..
just give your height and You will get height or even width if wanted.
/**
* Get the view height before the view will render
* #param view the view to measure
* #return the height of the view
*/
public static int getViewHeight(View view) {
WindowManager wm =
(WindowManager) view.getContext().getSystemService(Context.WINDOW_SERVICE);
Display display = wm.getDefaultDisplay();
int deviceWidth;
if(android.os.Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB_MR2){
Point size = new Point();
display.getSize(size);
deviceWidth = size.x;
} else {
deviceWidth = display.getWidth();
}
int widthMeasureSpec = View.MeasureSpec.makeMeasureSpec(deviceWidth, View.MeasureSpec.AT_MOST);
int heightMeasureSpec = View.MeasureSpec.makeMeasureSpec(0, View.MeasureSpec.UNSPECIFIED);
view.measure(widthMeasureSpec, heightMeasureSpec);
return view.getMeasuredHeight(); // view.getMeasuredWidth();
}
In Kotlin you can simply do this:
fr.post {
height=fr.height
width=fr.width
}
If you get -1 or -2 it could also be the numeric value of LayoutParams.WRAP_CONTENT (-2) or LayoutParams.MATCH_PARENT (-1).
I had same issue but didn't want to draw on screen before measuring so I used this method of measuring the view before trying to get the height and width.
Example of use:
layoutView(view);
int height = view.getHeight();
//...
void layoutView(View view) {
view.setDrawingCacheEnabled(true);
int wrapContentSpec =
MeasureSpec.makeMeasureSpec(MeasureSpec.UNSPECIFIED, MeasureSpec.UNSPECIFIED);
view.measure(wrapContentSpec, wrapContentSpec);
view.layout(0, 0, view.getMeasuredWidth(), view.getMeasuredHeight());
}
Most easiest way is to use ViewTreeObserver, if you directly use .height or .width you get values as 0, due to views are not have size until they draw on our screen. Following example will show how to use ViewTreeObserver
ViewTreeObserver viewTreeObserver = YOUR_VIEW_TO_MEASURE.getViewTreeObserver();
if (viewTreeObserver.isAlive()) {
viewTreeObserver.addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {
#Override
public void onGlobalLayout() {
YOUR_VIEW_TO_MEASURE.getViewTreeObserver().removeOnGlobalLayoutListener(this);
int viewHeight = YOUR_VIEW_TO_MEASURE.getHeight();
int viewWeight = YOUR_VIEW_TO_MEASURE.getWidth();
}
});
}
if you need to use this on method, use like this and to save the values you can use globle variables.
try with this metods:
int width = mView.getMeasuredWidth();
int height = mView.getMeasuredHeight();
Or
int width = mTextView.getMeasuredWidth();
int height = mTextView.getMeasuredHeight();
try something like this code from this link
ViewTreeObserver viewTreeObserver = view.getViewTreeObserver();
if (viewTreeObserver.isAlive()) {
viewTreeObserver.addOnGlobalLayoutListener(new OnGlobalLayoutListener() {
#Override
public void onGlobalLayout() {
view.getViewTreeObserver().removeGlobalOnLayoutListener(this);
viewWidth = view.getWidth();
viewHeight = view.getHeight();
}
});
}
hope this helps.
As I just ran into this problem thought I would write it for kotlin,
my_view.viewTreeObserver.addOnGlobalLayoutListener {
// here your view is measured
// get height using my_view.height
// get width using my_view.width
}
or
my_view.post {
// here your view is measured
// get height using my_view.height
// get width using my_view.width
}
If you code in Kotlin use this nice extension function :
inline fun View.getDimensions(crossinline onDimensionsReady: (Int, Int) -> Unit) {
lateinit var layoutListener: ViewTreeObserver.OnGlobalLayoutListener
layoutListener = ViewTreeObserver.OnGlobalLayoutListener {
viewTreeObserver.removeOnGlobalLayoutListener(layoutListener)
onDimensionsReady(width, height)
}
viewTreeObserver.addOnGlobalLayoutListener(layoutListener)
}
Usage :
view.getDimensions { width, height ->
println("width = $width")
println("height = $height")
}
The first snippet is correct, but you need to call it after onMeasure() gets executed. Otherwise the size is not yet measured for the view.
For frame:
height=fr.getHeight();
width=fr.getWidth();
For screen:
width = getWindowManager().getDefaultDisplay().getWidth();
height = getWindowManager().getDefaultDisplay().getHeight();
I used DisplayMetrics to get the screen size and then i can assign the width/height to an element in %age
It will be like this
DisplayMetrics dmetrics = new DisplayMetrics();
int widthPixels=dmetrics.widthPixels;
int heightPixels=dmetrics.heightPixels;
//setting the height of the button
button_nextPuzzle.setMinHeight((int) ((heightPixels/3)*.30));
Worked for me very well!!!
Check behavior
Very Simple Solution
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
Log.d(LOG, "MainActivity - onCreate() called")
fragments_frame.post {
Log.d(LOG, " fragments_frame.height:${fragments_frame.width}")
Log.d(LOG, " fragments_frame.height:${fragments_frame.measuredWidth}")
}
}
getDefaultDisplay().getHeight is deprecated. So better to use
getResources().getDisplayMetrics().heightPixels;
you can use coroutines as well, like this one :
CoroutineScope(Dispatchers.Main).launch {
delay(10)
val width = view.width()
val height= view.height()
// do your job ....
}
I am trying to get the list view heigh at run time to fit the item to height of screen.
Here is my code: in my getView()
int totalHeight = activity.getListView().getHeight();
int rowHeight = totalHeight / getCount(); // Divide by number of items.
activity.getListView().setScrollContainer(false);
activity.getListView().setVerticalScrollBarEnabled(false);
convertView.setMinimumHeight(rowHeight);
In my activity i have programatically created List View with both width and height as MATCH_PARENT.
But i tried to debug and saw that only for the first item the list view height is 0 but for rest of the items its giving me proper height.
Why so
? how to fix this ?
It's most probably due to that the view has not been created yet. In this situation the height would be 0.
You can get the height of the view using something like:
final ListView listView = activity.getListView();
ViewTreeObserver vto = listView.getViewTreeObserver();
vto.addOnGlobalLayoutListener(new OnGlobalLayoutListener() {
#Override
public void onGlobalLayout() {
int totalHeight = listView.getHeight();
int rowHeight = totalHeight / getCount(); // Divide by number of items.
listView.setScrollContainer(false);
listView.setVerticalScrollBarEnabled(false);
convertView.setMinimumHeight(rowHeight);
ViewTreeObserver obs = listView.getViewTreeObserver();
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN) {
obs.removeOnGlobalLayoutListener(this);
} else {
obs.removeGlobalOnLayoutListener(this);
}
}
});
The reason for checking the Build.VERSION is that in the SDK prior to Jelly Bean the name of the method was different (OnGlobalLayout vs GlobalOnLayout)
It is happening because when the getView for the first item was called the height of the listview is not determined.
you need to use ViewTreeObserver to give you an event for layout change and in that you can get the height.
These methods return correct values when retrieved dynamically for eg. in onCreate() , but the only exception is when the dimension is specified in the xml layout file as undefined ,
like 'wrap content' etc. Is there a way to retrieve such values too ???
This should return the correct width and height. onCreate is called before the layout of the child views are done. So the width and height is not calculated yet. To get the height and width. Put this on the onCreate method
LinearLayout layout = (LinearLayout)findViewById(R.id.YOUD VIEW ID);
ViewTreeObserver vto = layout.getViewTreeObserver();
vto.addOnGlobalLayoutListener(new OnGlobalLayoutListener() {
#Override
public void onGlobalLayout() {
hs.getViewTreeObserver().removeGlobalOnLayoutListener(this);
int width = layout.getMeasuredWidth();
int height = layout.getMeasuredHeight();
}
});
I have a full-screen TextView holding a long Spanned that requires scrolling. The TextView's getLineCount() gives me the total number of lines used for the entire block of text but I'd like to know how many lines of text are currently visible on the screen.
Or, better yet, is there a way to figure out the range of lines currently visible on the screen? For example, as the view scrolls, can I tell that lines 20-60 are currently visible?
I figured out the answer:
int height = myTextView.getHeight();
int scrollY = myTextView.getScrollY();
Layout layout = myTextView.getLayout();
int firstVisibleLineNumber = layout.getLineForVertical(scrollY);
int lastVisibleLineNumber = layout.getLineForVertical(scrollY+height);
To make them work you should write the code posted by #Robert in this way:
ViewTreeObserver vto = txtViewEx.getViewTreeObserver();
vto.addOnGlobalLayoutListener(new OnGlobalLayoutListener() {
#Override
public void onGlobalLayout() {
ViewTreeObserver obs = txtViewEx.getViewTreeObserver();
obs.removeOnGlobalLayoutListener(this);
height = txtViewEx.getHeight();
scrollY = txtViewEx.getScrollY();
Layout layout = txtViewEx.getLayout();
firstVisibleLineNumber = layout.getLineForVertical(scrollY);
lastVisibleLineNumber = layout.getLineForVertical(height+scrollY);
}
});