I am using ListView inside ScrollView and as we all know It creates problem.
I got good solution from this website : How to calculate total row heights of listView in android?
But still for some items, It does not show Listview properly. Is there any improved solution ?
My Code :
public static void getListViewSize(ListView myListView, Context context) {
ListAdapter myListAdapter = myListView.getAdapter();
if (myListAdapter == null) {
return;
}
int totalHeight = 0;
for (int size = 0; size < myListAdapter.getCount(); size++) {
View listItem = myListAdapter.getView(size, null, myListView);
if (listItem instanceof ViewGroup)
listItem.setLayoutParams(new RelativeLayout.LayoutParams(
RelativeLayout.LayoutParams.WRAP_CONTENT,
RelativeLayout.LayoutParams.WRAP_CONTENT));
WindowManager wm = (WindowManager) context
.getSystemService(Context.WINDOW_SERVICE);
Display display = wm.getDefaultDisplay();
#SuppressWarnings("deprecation")
int screenWidth = display.getWidth();
int listViewWidth = screenWidth - 20;
int widthSpec = MeasureSpec.makeMeasureSpec(listViewWidth,
MeasureSpec.AT_MOST);
listItem.measure(widthSpec, 0);
totalHeight += listItem.getMeasuredHeight();
Log.e("height of listItem:", String.valueOf(totalHeight));
}
ViewGroup.LayoutParams params = myListView.getLayoutParams();
params.height = totalHeight
+ (myListView.getDividerHeight() * (myListAdapter.getCount() - 1));
myListView.setLayoutParams(params);
myListView.requestLayout();
}
View listItem = listAdapter.getView(i, null, listView);
listItem.measure(0, 0);
totalHeight += listItem.getMeasuredHeight();
The core of the function is these three lines, it try to measure each view. The 0 in listItem.measure(0, 0) is equals to MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED)
Mostly it will calculate the accurate height of the listview. There is one exception, when the view content is too much and will wrap line, i.e. there are to many lines of text. In such situation, you should specified a accurate widthSpec to measure(). So change listItem.measure(0, 0) to
// try to give a estimated width of listview
int listViewWidth = screenWidth - leftPadding - rightPadding;
int widthSpec = MeasureSpec.makeMeasureSpec(listViewWidth, MeasureSpec.AT_MOST);
listItem.measure(listViewWidth, 0)
UPDATE about the formula here
int listViewWidth = screenWidth - leftPadding - rightPadding;
enter code here
It's just an example to show how you can estimate the width of the width of listview, the formula is based on the fact that width of listview ≈ width of screen. The padding is set by your self, maybe 0 here (Get screen dimensions in pixels). This page tells how to get screen width. In general, it's just a sample, and you can write your own formula here.
Related
I need to Implement the list view inside scroll view.
i knw it's not good idea using listview inside scroll view but it's requirenment of app so i need to implement it.
In app im using TabLayout with 3 type of tabs like categories 1,categories 2 and again categories 3 to filter the data.
in first tab categories 1 i need to add 2 list view one is fix items and second is dynamic.
Fist list view is fixed so i can give fixed height to it.
but second List view is dynamic so i need to give height according to the total number of values in list view.
im try many ways to give dynamic height but not getting the task done.
here is method i alredy try :-
-------------------first -------------------------------
first from question
Android: How to measure total height of ListView
public static void getTotalHeightofListView(ListView listView) {
ListAdapter mAdapter = listView.getAdapter();
int totalHeight = 0;
for (int i = 0; i < mAdapter.getCount(); i++) {
View mView = mAdapter.getView(i, null, listView);
mView.measure(
View.MeasureSpec.makeMeasureSpec(0, View.MeasureSpec.UNSPECIFIED),
View.MeasureSpec.makeMeasureSpec(0, View.MeasureSpec.UNSPECIFIED));
totalHeight += mView.getMeasuredHeight();
Log.w("HEIGHT" + i, String.valueOf(totalHeight));
}
ViewGroup.LayoutParams params = listView.getLayoutParams();
params.height = totalHeight
+ (listView.getDividerHeight() * (mAdapter.getCount() - 1));
listView.setLayoutParams(params);
listView.requestLayout();
}
-------------------second-------------------------------
from question
https://stackoverflow.com/questions/17693578
public static class ListUtils {
public static void setDynamicHeight(ListView mListView) {
ListAdapter mListAdapter = mListView.getAdapter();
if (mListAdapter == null) {
// when adapter is null
return;
}
int height = 0;
int desiredWidth = MeasureSpec.makeMeasureSpec(mListView.getWidth(), MeasureSpec.UNSPECIFIED);
for (int i = 0; i < mListAdapter.getCount(); i++) {
View listItem = mListAdapter.getView(i, null, mListView);
listItem.measure(desiredWidth, MeasureSpec.UNSPECIFIED);
height += listItem.getMeasuredHeight();
}
ViewGroup.LayoutParams params = mListView.getLayoutParams();
params.height = height + (mListView.getDividerHeight() * (mListAdapter.getCount() - 1));
mListView.setLayoutParams(params);
mListView.requestLayout();
}
}
-------------------error-------------------
In your activity xml file, you can use LinearLayout inside the ScrollView and then can assign android:weight attribute to them.
You can assign weight to the single element and all other element ajust at their own available space.
Better practice, it's using list that support dynamic changes of view. And for your question there is special list - LinkedListView
I used this code to get the total heights of listview row items but it did not returns the actual height. Here is the used code
public static void setListViewHeightBasedOnChildren(ListView listView) {
ListAdapter listAdapter = listView.getAdapter();
if (listAdapter == null) {
// pre-condition
return;
}
int totalHeight = 0;
for (int i = 0; i < listAdapter.getCount(); i++) {
View listItem = listAdapter.getView(i, null, listView);
listItem.measure(0, 0);
totalHeight += listItem.getMeasuredHeight();
}
ViewGroup.LayoutParams params = listView.getLayoutParams();
params.height = totalHeight + (listView.getDividerHeight() * (listAdapter.getCount() - 1));
listView.setLayoutParams(params);
listView.requestLayout();
}
For example: I have a listview with 20 rows and each rows height is different from each others suppose that 200,300,500. When I use this above code, it did not returns actual height for me. Also I tried this answer : Android: How to measure total height of ListView
But did not works. How can I get rid of this problem. Can anyone explain this solution??
View listItem = listAdapter.getView(i, null, listView);
listItem.measure(0, 0);
totalHeight += listItem.getMeasuredHeight();
The core of the function is these three lines, it try to measure each view. The 0 in listItem.measure(0, 0) is equals to MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED)
Mostly it will calculate the accurate height of the listview. There is one exception, when the view content is too much and will wrap line, i.e. there are to many lines of text. In such situation, you should specified a accurate widthSpec to measure(). So change listItem.measure(0, 0) to
// try to give a estimated width of listview
int listViewWidth = screenWidth - leftPadding - rightPadding;
int widthSpec = MeasureSpec.makeMeasureSpec(listViewWidth, MeasureSpec.AT_MOST);
listItem.measure(listViewWidth, 0)
UPDATE about the formula here
int listViewWidth = screenWidth - leftPadding - rightPadding;
It's just an example to show how you can estimate the width of the width of listview, the formula is based on the fact that width of listview ≈ width of screen. The padding is set by your self, maybe 0 here. This page tells how to get screen width.
In general, it's just a sample, and you can write your own formula here.
This question already has answers here:
Calculate the size of a list view or how to tell it to fully expand
(12 answers)
Closed 10 years ago.
I need to measure total height of the ListView but it seems I'm constantly getting wrong values. I'm using this code:
public static void setListViewHeightBasedOnChildren(ListView listView) {
ListAdapter listAdapter = listView.getAdapter();
if (listAdapter == null) {
return;
}
int totalHeight = 0;
int desiredWidth = MeasureSpec.makeMeasureSpec(listView.getWidth(),
MeasureSpec.AT_MOST);
Log.w("DESIRED WIDTH", String.valueOf(listAdapter.getCount()));
for (int i = 0; i < listAdapter.getCount(); i++) {
View listItem = listAdapter.getView(i, null, listView);
listItem.measure(desiredWidth, MeasureSpec.UNSPECIFIED);
totalHeight += listItem.getMeasuredHeight();
Log.w("HEIGHT"+i, String.valueOf(totalHeight));
}
ViewGroup.LayoutParams params = listView.getLayoutParams();
params.height = totalHeight
+ (listView.getDividerHeight() * (listAdapter.getCount() - 1));
listView.setLayoutParams(params);
listView.requestLayout();
}
Problem is that I'm receiving larger height than I should receive. Every list item is measured differently and all items have the same height so it definitely shouldn't do that. Height of each element is at least double of it's real height.
Thank you in advance.
edit1:
I have two ListViews and they both have items with 6-7 EditText fields. I show/hide ListView if user wants to write/delete values in EditText. Everything works well except when I want to show list, it takes a lot of space because method calculated ListView needs a lot of space. Because of that I have a lot of empty space below that ListView. Like three times more empty space that needed.
Finally I've done it! This is the working code which measures ListView height and sets ListView in full size:
public static void getTotalHeightofListView(ListView listView) {
ListAdapter mAdapter = listView.getAdapter();
int totalHeight = 0;
for (int i = 0; i < mAdapter.getCount(); i++) {
View mView = mAdapter.getView(i, null, listView);
mView.measure(
MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED),
MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED));
totalHeight += mView.getMeasuredHeight();
Log.w("HEIGHT" + i, String.valueOf(totalHeight));
}
ViewGroup.LayoutParams params = listView.getLayoutParams();
params.height = totalHeight
+ (listView.getDividerHeight() * (mAdapter.getCount() - 1));
listView.setLayoutParams(params);
listView.requestLayout();
}
Try something like this :
listItem.getViewTreeObserver().addOnGlobalLayoutListener(new OnGlobalLayoutListener() {
public void onGlobalLayout() {
int listItemHeight = listItem.getHeight();
}
});
If you want the height of the listView then try this :
listView.getViewTreeObserver().addOnGlobalLayoutListener(new OnGlobalLayoutListener() {
public void onGlobalLayout() {
int listViewHeight = listView.getHeight();
}
});
You could also check this : Calculate the size of a list view or how to tell it to fully expand
ListView caches the view items and reuses them. If you have a list view with 1000 items and only 6 visible, why, it's not worth rendering the 994 not showing.
Measuring the whole ListView would mean render every ListItem, seems a bit overkill.
I don't know what you are trying to achieve but there's probably a better way :)
{ January 14, 2011... I have given up to use setListViewHeightBasedOnChildren(ListView listView},
instead, I don't put my listview in a scrollview, and then just put other contents
into a listview by using ListView.addHeaderView() and ListView.addFooterView().
http://dewr.egloos.com/5467045 }
ViewGroup(the ViewGroup is containing TextViews having long text except line-feed-character).getMeasuredHeight returns wrong value... that is smaller than real height.
how to get rid of this problem?
here is the java code:
/*
I have to set my listview's height by myself. because
if a listview is in a scrollview then that will be
as short as the listview's just one item.
*/
public static void setListViewHeightBasedOnChildren(ListView listView) {
ListAdapter listAdapter = listView.getAdapter();
if (listAdapter == null) {
// pre-condition
return;
}
int totalHeight = 0;
int count = listAdapter.getCount();
for (int i = 0; i < count; i++) {
View listItem = listAdapter.getView(i, null, listView);
listItem.measure(View.MeasureSpec.AT_MOST, View.MeasureSpec.UNSPECIFIED);
totalHeight += listItem.getMeasuredHeight();
}
ViewGroup.LayoutParams params = listView.getLayoutParams();
params.height = totalHeight + (listView.getDividerHeight() * (listAdapter.getCount() - 1));
listView.setLayoutParams(params);
}
and here is the list_item_comments.xml:
The question is rather old, but I had similar problem, so I'll describe what was wrong.
Actually, parameters in listItem.measure() are used wrong, you should set something like this:
listItem.measure(MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED), MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED))
However, be careful with unspecified width measure spec, it will ignore all layout params and even screen dimensions, so to get correct height, first get maximum width View can use and call measure() this way:
listItem.measure(MeasureSpec.makeMeasureSpec(maxWidth, MeasureSpec.AT_MOST), MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED));
This is the only solution i have found so far.
http://syedrakibalhasan.blogspot.com/2011/02/how-to-get-width-and-height-dimensions.html
It also gives wrong value when Your xml file of listview item has padding. Remove padding, try using margin and it will work perfectly.
I have three ListView widgets in the same LinearLayout. Something like this (I'm omitting XML elements that are not relevant in this example):
<LinearLayout>
<ListView
android:layout_width="fill_parent"
android:layout_height="360dp"/>
<ListView
android:layout_width="fill_parent"
android:layout_height="360dp"/>
<ListView
android:layout_width="fill_parent"
android:layout_height="360dp"/>
</LinearLayout>
This forces the list to have a height of 360 dip. Of course, that will be its height even if there are few list items. So, my question is how can make the lists have an automatic height? What I want is that the ListView height takes the exact size of the sum of all its list items.
I've implemented it this way (code is work in progress so it's more a idea source than solution):
package com.customcontrols;
public class NoScrollListView extends ListView
{
#Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec)
{
super.onMeasure(widthMeasureSpec, MeasureSpec.makeMeasureSpec(MeasureSpec.UNSPECIFIED, 0) );
// here I assume that height's being calculated for one-child only, seen it in ListView's source which is actually a bad idea
int childHeight = getMeasuredHeight() - (getListPaddingTop() + getListPaddingBottom() + getVerticalFadingEdgeLength() * 2);
int fullHeight = getListPaddingTop() + getListPaddingBottom() + childHeight*(getCount());
setMeasuredDimension(getMeasuredWidth(), fullHeight);
}
}
the calculation's not perfect, but it's close and works so far.
after that you just create a layout like this:
ScrollView
com.customcontrol.NoScrollListView
com.customcontrol.NoScrollListView
com.customcontrol.NoScrollListView
/ScrollView
The scrollView's crucial since you can easily run out of screen bounds.
PS. The calculation's rectum-driven since most of the calculation methods in ListView&Co are package private which is quite a strange choice for publicly inheritable classes for UI.
Instead of editing my previous answer, here's my actual version (after finally the case became the issue and I had to fix it)
#Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec)
{
super.onMeasure(widthMeasureSpec, MeasureSpec.makeMeasureSpec(MeasureSpec.UNSPECIFIED, 0));
int childHeight = getMeasuredHeight() - (getListPaddingTop() + getListPaddingBottom() + getVerticalFadingEdgeLength() * 2);
// on a first run let's have a space for at least one child so it'll trigger remeasurement
int fullHeight = getListPaddingTop() + getListPaddingBottom() + childHeight*(getCount());
int newChildHeight = 0;
for (int x = 0; x<getChildCount(); x++ ){
View childAt = getChildAt(x);
if (childAt != null) {
int height = childAt.getHeight();
newChildHeight += height;
}
}
//on a second run with actual items - use proper size
if (newChildHeight != 0)
fullHeight = getListPaddingTop() + getListPaddingBottom() + newChildHeight;
setMeasuredDimension(getMeasuredWidth(), fullHeight);
}
The trickiest part is that the onMeasure gets called twice, first for approx layout and then after items added for a precise one and both have to return sane results.
i found a solution on set ListView Height Based On Children, this work
public static void setListViewHeightBasedOnChildren(ListView listView) {
ListAdapter listAdapter = listView.getAdapter();
if (listAdapter == null) {
// pre-condition
return;
}
int totalHeight = 0;
for (int i = 0; i < listAdapter.getCount(); i++) {
View listItem = listAdapter.getView(i, null, listView);
listItem.measure(0, 0);
totalHeight += listItem.getMeasuredHeight();
}
ViewGroup.LayoutParams params = listView.getLayoutParams();
params.height = totalHeight + (listView.getDividerHeight() * (listAdapter.getCount() - 1));
listView.setLayoutParams(params);
listView.requestLayout();
}
try this... list view real height
list view xml coding
<ListView
android:id="#+id/my_listview"
android:layout_width="match_parent"
android:layout_height="match_parent" />
list view java coding
ListView lView = (ListView)findViewById(R.id.my_listview);
lView.setAdapter(adapter);
setListViewHeightBasedOnChildren(lView);
setListViewHeightBasedOnChildren method
public static void setListViewHeightBasedOnChildren(ListView listView) {
ListAdapter listAdapter = listView.getAdapter();
if (listAdapter == null) {
return;
}
int totalHeight = 0;
for (int i = 0; i < listAdapter.getCount(); i++) {
View listItem = listAdapter.getView(i, null, listView);
listItem.measure(0, 0);
totalHeight += listItem.getMeasuredHeight();
}
ViewGroup.LayoutParams params = listView.getLayoutParams();
params.height = totalHeight + (listView.getDividerHeight() * (listAdapter.getCount() - 1));
listView.setLayoutParams(params);
listView.requestLayout();
}
You can try iterating over the ListView's rows (see methods on ViewGroup), find their heights, sum them, and change your ListView height.
That being said, I fully expect this to be awful:
You need to take into account the screen size, so your lists do not go past the bounds of the screen
You need to take into account orientation changes
You need to take into account any modifications to your data (e.g., deleting rows may require your list to shrink)
Etc.
If your goal really is to have a single list, but you have three sources of data, merge the data and put it into a single list. My MergeAdapter can help here.