I am using expandable list view to make 3 - level hierarchy, would like to know how to set internal list height and width.
I knew we have onMeasure for this purpose but in my case it not allowing me to capture whole space of parent list view.
may be I am giving wrong value to it, here is the code which is I am using for setting height and width of child expandable list.
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec)
{
widthMeasureSpec = MeasureSpec.makeMeasureSpec(960,MeasureSpec.AT_MOST);
heightMeasureSpec = MeasureSpec.makeMeasureSpec(800,MeasureSpec.AT_MOST);
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
}
Currently it appearing as follow
<ParentGroup1 >
<ChildParentGroup>
<Child1>
<Child2>
<child3>
<ParentGroup2 >
and it should appear like below.
<ParentGroup1 >
<ChildParentGroup >
<Child1 >
<Child2 >
<child3 >
<ParentGroup2 >
Please advise/suggest for the same.
Thanks for your time.
Not sure if you're still looking for an answer, but this is how I did it: pass a reference to the parent view and a height measure (in this case, I used the size of the child list) in the constructor to create the child custom list.
public CustomExpandableList(Context context, View the_parentView, int the_heightMeasure)
{
super(context);
WIDTH = the_parentView!=null?the_parentView.getWidth():LayoutParams.MATCH_PARENT;
HEIGHT = the_heightMeasure * 500;
}
EDIT: Or to make the code more consistent, you could pass the width of the parentView and height measure to the constructor instead of passing the parent view itself.
CustomExpandableList(Context the_context, int the_width, int the_heightMeasure)
use this code to calculate expandable list view dynamically:
// calculate the height of expandable listView without expanded
private void setListViewHeight(ExpandableListView expListView) {
ListAdapter listAdapter = expListView.getAdapter();
int totalHeight = 0;
for (int i = 0; i < listAdapter.getCount(); i++) {
View listItem = listAdapter.getView(i, null, expListView);
listItem.measure(0, 0);
totalHeight += listItem.getMeasuredHeight();
System.out.println("i " + i);
}
ViewGroup.LayoutParams params = expListView.getLayoutParams();
params.height = totalHeight
+ (expListView.getDividerHeight() * (listAdapter.getCount() - 1));
System.out.println("params.height = " + params.height);
expListView.setLayoutParams(params);
expListView.requestLayout();
}
// calculate the height of expandable listview dynamically
private void setListViewHeight(ExpandableListView expListView, int group) {
ExpandableListAdapter listAdapter = expListView
.getExpandableListAdapter();
int totalHeight = 0;
int desiredWidth = MeasureSpec.makeMeasureSpec(expListView.getWidth(),
MeasureSpec.UNSPECIFIED);
for (int i = 0; i < listAdapter.getGroupCount(); i++) {
View groupItem = listAdapter.getGroupView(i, false, null,
expListView);
groupItem.measure(desiredWidth, MeasureSpec.UNSPECIFIED);
totalHeight += groupItem.getMeasuredHeight();
if (((expListView.isGroupExpanded(i)) && (i == group))
|| ((!expListView.isGroupExpanded(i)) && (i == group))) {
for (int j = 0; j < listAdapter.getChildrenCount(i); j++) {
View listItem = listAdapter.getChildView(i, j, false, null,
expListView);
Log.e("Count", listAdapter.getChildrenCount(i) + "");
listItem.setLayoutParams(new ViewGroup.LayoutParams(
desiredWidth, MeasureSpec.UNSPECIFIED));
// listItem.measure(desiredWidth, MeasureSpec.UNSPECIFIED);
listItem.measure(MeasureSpec.makeMeasureSpec(0,
MeasureSpec.UNSPECIFIED), MeasureSpec
.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED));
totalHeight += listItem.getMeasuredHeight();
System.out.println("totalHeight" + totalHeight);
Log.e("TEST", "gshdkfmjfy,");
}
}
}
ViewGroup.LayoutParams params = expListView.getLayoutParams();
int height = totalHeight
+ (expListView.getDividerHeight() * (listAdapter
.getGroupCount() - 1));
if (height < 10) {
height = 100;
}
params.height = height;
expListView.setLayoutParams(params);
expListView.requestLayout();
}
I succeeded in some days ago by doing this. It's a little bit more compact and without any additionnal parameter, and it works perfectly.
public static void setExpandableListViewHeightBasedOnChildren(ExpandableListView expandableListView){
ExpandableNotesListAdapter adapter = (ExpandableNotesListAdapter) expandableListView.getExpandableListAdapter();
if (adapter == null){
return;
}
int totalHeight = expandableListView.getPaddingTop() + expandableListView.getPaddingBottom();
for (int i = 0 ; i < adapter.getGroupCount() ; i++){
View groupItem = adapter.getGroupView(i, false, null, expandableListView);
groupItem.measure(View.MeasureSpec.UNSPECIFIED,View.MeasureSpec.UNSPECIFIED);
totalHeight += groupItem.getMeasuredHeight();
if (expandableListView.isGroupExpanded(i) ){
for( int j = 0 ; j < adapter.getChildrenCount(i) ; j++) {
View listItem = adapter.getChildView(i, j, false, null, expandableListView);
listItem.setLayoutParams(new LayoutParams(View.MeasureSpec.UNSPECIFIED, View.MeasureSpec.UNSPECIFIED));
listItem.measure(View.MeasureSpec.makeMeasureSpec(0,
View.MeasureSpec.UNSPECIFIED), View.MeasureSpec
.makeMeasureSpec(0, View.MeasureSpec.UNSPECIFIED));
totalHeight += listItem.getMeasuredHeight();
}
}
}
ViewGroup.LayoutParams params = expandableListView.getLayoutParams();
int height = totalHeight + expandableListView.getDividerHeight() * (adapter.getGroupCount() - 1);
if (height < 10)
height = 100;
params.height = height;
expandableListView.setLayoutParams(params);
expandableListView.requestLayout();
}
Don't forget to add this when you init your View, set your adapter, etc. :
Functions.setExpandableListViewHeightBasedOnChildren(listView);
listView.setOnGroupExpandListener(new ExpandableListView.OnGroupExpandListener() {
#Override
public void onGroupExpand(int groupPosition) {
Functions.setExpandableListViewHeightBasedOnChildren(listView);
}
});
Create one layout xml file for ParentGroup and ChildParentGroup , another layout xml file for Child. Now you are problem is reduced to two level hierarchy. Then In Expandable listview we have Parent view and childview methods to inflate and use the Parent and Child layouts. So in that mehods you can do whatever you want.
Simply remove the width code and it should work fine.
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec)
{
heightMeasureSpec = MeasureSpec.makeMeasureSpec(999999, MeasureSpec.AT_MOST);
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
}
I know its late, but if anyone has the same issue. You can solve it by creating a Custom ExpandableListView and using "MeasureSpec.EXACTLY":
public class CustomExpListView extends ExpandableListView{
public CustomExpListView(Context context){
super(context);
}
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec){
widthMeasureSpec = MeasureSpec.makeMeasureSpec(960, MeasureSpec.EXACTLY);
heightMeasureSpec = MeasureSpec.makeMeasureSpec(20000, MeasureSpec.AT_MOST);
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
}
}
Hope this helps to anyone. For me its working.
Adding to muhammadSalem's answer. This is how I solved my problem by calculating the height of expandableListView's children's total height.
private fun getSubItemTotalHeight(groupPosition: Int): Int {
val children: Int = mAdapter.getChildrenCount(groupPosition)
val desiredWidth: Int = View.MeasureSpec.makeMeasureSpec(mExpandableListView.width,
View.MeasureSpec.UNSPECIFIED)
var subItemTotalHeight = 0
repeat(children) {
val child = mAdapter.getChildView(groupPosition, it, true, null, null)
child.layoutParams = ViewGroup.LayoutParams(
desiredWidth, View.MeasureSpec.UNSPECIFIED)
child.measure(View.MeasureSpec.makeMeasureSpec(0,
View.MeasureSpec.UNSPECIFIED), View.MeasureSpec
.makeMeasureSpec(0, View.MeasureSpec.UNSPECIFIED))
subItemTotalHeight += child.measuredHeight
}
val dividerCount = children - 1
val dividerTotalCount = (dividerCount * mExpandableListView.dividerHeight).toFloat()
showToast(mExpandableListView.dividerHeight.toString())
val totalDividerPixels = TypedValue.applyDimension(
TypedValue.COMPLEX_UNIT_DIP,
dividerTotalCount,
resources.displayMetrics
)
return subItemTotalHeight + totalDividerPixels.toInt()
}
One thing to note is that if you added a divider height for your expandableListview, you should include the calculations for it. What I did is convert the total divider height which is in dp into pixels and added it into the totalHeight. This solved the clipping issues I encountered.
Then to use it would be just :
mExpandableListView.setOnGroupExpandListener { groupPosition ->
mExpandableListView.layoutParams.height += getSubItemTotalHeight(groupPosition)
mExpandableListView.requestLayout()
}
mExpandableListView.setOnGroupCollapseListener { groupPosition ->
mExpandableListView.layoutParams.height -= getSubItemTotalHeight(groupPosition)
mExpandableListView.requestLayout()
}
Related
I'm trying to dynamically add items to the my CustomView and make the final height the size of all the children added together. The only problem is the child.getMeasuredHeight or child.getMeasuredWidth always returns a value of 0 during run time. When I'm debugging it will randomly 1 out of 10 times seem to actually contain the data I was actually expecting with a value of 192. If I also hard code a value into the layout parameter instead of using WRAP_CONTENT it still shows a value of 0. Is there something that I'm doing wrong.
xml file
<CustomLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_marginTop="80dp"
android:orientation="vertical"
android:layout_width="200dp"
android:layout_height="100dp"
android:id="#+id/custom_layout"
android:background="#drawable/custom_shape"/>
</CustomLayout>
Here's a part of my CustomLayout.java class
public class CustomLayout extends LinearLayout {
public CustomLayout(Context context, AttributeSet attrs) {
super(context, attrs);
}
public CustomLayout(Context context) {
super(context);
}
#Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
int count = getChildCount();
int maxHeight = 0;
int maxWidth = 0;
int widthSize = MeasureSpec.getSize(widthMeasureSpec);
int heightSize = MeasureSpec.getSize(heightMeasureSpec);
for(int i=0; i <count; i++) {
final View child = getChildAt(i);
if(child.getVisibility() != GONE) {
maxHeight += child.getMeasuredHeight();
}
}
setMeasuredDimension(widthSize,maxHeight);
}
In a part of my main activity
Button b = new Button(this);
b.setLayoutParams(new ViewGroup.LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT));
b.setText("Sample Test");
b.setTextSize(14);
mCustomView.addView(b);
You will need to ask each child of the ViewGroup to measure itself before you can access its dimensions. This is done with a call to [measureChild](https://developer.android.coma/reference/android/view/ViewGroup.html#measureChild(android.view.View, int, int)) or [measureChildWithMargins](https://developer.android.coma/reference/android/view/ViewGroup.html#measureChild(android.view.View, int, int)).
Take a look at the developer guide for ViewGroup to see how the child measurements are obtained.
// Iterate through all children, measuring them and computing our dimensions
// from their size.
for (int i = 0; i < count; i++) {
final View child = getChildAt(i);
if (child.getVisibility() != GONE) {
// Measure the child.
measureChildWithMargins(child, widthMeasureSpec, 0, heightMeasureSpec, 0);
// Update our size information based on the layout params. Children
// that asked to be positioned on the left or right go in those gutters.
final LayoutParams lp = (LayoutParams) child.getLayoutParams();
if (lp.position == LayoutParams.POSITION_LEFT) {
mLeftWidth += Math.max(maxWidth,
child.getMeasuredWidth() + lp.leftMargin + lp.rightMargin);
} else if (lp.position == LayoutParams.POSITION_RIGHT) {
mRightWidth += Math.max(maxWidth,
child.getMeasuredWidth() + lp.leftMargin + lp.rightMargin);
} else {
maxWidth = Math.max(maxWidth,
child.getMeasuredWidth() + lp.leftMargin + lp.rightMargin);
}
maxHeight = Math.max(maxHeight,
child.getMeasuredHeight() + lp.topMargin + lp.bottomMargin);
childState = combineMeasuredStates(childState, child.getMeasuredState());
}
}
I had a problem that stems from the fact that Android has certain difficulty with nested scrolling elements.
I have a ScrollView that hosts a horizontal RecyclerView and an ExpandableListView just beneath it.
The issue I encountered was that the ScrollView didn't scroll.
I fixed it by :
1. setting fixed height to the RecyclerView.
2. calculating the ExpandableListView height with each group item click.
Like this:
expandableListView.setOnGroupClickListener(new ExpandableListView.OnGroupClickListener() {
#Override
public boolean onGroupClick(ExpandableListView parent, View v, int groupPosition, long id) {
setListViewHeight(parent, groupPosition);
return false;
}
});
private void setListViewHeight(ExpandableListView listView, int group) {
ExpandableListAdapter listAdapter = (ExpandableListAdapter) listView.getExpandableListAdapter();
int totalHeight = 0;
int desiredWidth = View.MeasureSpec.makeMeasureSpec(listView.getWidth(),View.MeasureSpec.EXACTLY);
for (int i = 0; i < listAdapter.getGroupCount(); i++) {
View groupItem = listAdapter.getGroupView(i, false, null, listView);
groupItem.measure(desiredWidth, View.MeasureSpec.UNSPECIFIED);
totalHeight += groupItem.getMeasuredHeight();
if (((listView.isGroupExpanded(i)) && (i != group)) || ((!listView.isGroupExpanded(i)) && (i == group)))
{
for (int j = 0; j < listAdapter.getChildrenCount(i); j++)
{
View listItem = listAdapter.getChildView(i, j, false, null,listView);
listItem.measure(desiredWidth, View.MeasureSpec.UNSPECIFIED);
totalHeight += listItem.getMeasuredHeight();
}
}
}
ViewGroup.LayoutParams params = listView.getLayoutParams();
int height = totalHeight + (listView.getDividerHeight() * (listAdapter.getGroupCount() - 1));
if (height < 10)
height = 200;
params.height = height;
listView.setLayoutParams(params);
listView.requestLayout();
}
Problem :
since I calculate the listview height only on group item click, when I just open the fragment and up until I click on a group item, the ScrollView doesn't work.
I have found that calculating the height of the ExpandableListView adapter in onCreateView is problematic since it is still empty at that point.
Any ideas would be much apreciated.
If you need to wait until the view has been laid out, you can use
a ViewTreeObserver. For example :
protected void onCreate(Bundle savedInstanceState) {
...
final View someView = findViewById(R.id.some_id);
someView.getViewTreeObserver().addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {
public void onGlobalLayout() {
// the values are now available
int mesuredHeight = someView.getMeasuredHeight();
int height = someView.getHeight();
// done, remove the observer
someView.getViewTreeObserver().removeOnGlobalLayoutListener(this);
}
});
...
}
In my application i am using StaggeredGridView and it is working fine. But when i placed it inside a scorllview and try to scroll it unfortunately the height of the StaggeredGridView is not matching with the exact grid view.
For controlling the scroll i am dynamically caluculating the height of the gridview and setting it to the gridview programatically by Based On Children items. i think it will be the problem..
here the main problem is item heights will be not same like normal gridview.
Here is my code for setGridViewHeightBasedOnChildren
public static void setListViewHeightBasedOnChildren(StaggeredGridView listView) {
SampleAdapter listAdapter = (SampleAdapter) listView.getAdapter();
if (listAdapter == null)
return;
int desiredWidth = MeasureSpec.makeMeasureSpec(listView.getWidth(), MeasureSpec.UNSPECIFIED);
int totalHeight = 0;
View view = null;
for (int i = 0; i < listAdapter.getCount(); i++) {
view = listAdapter.getView(i, view, listView);
if (i == 0)
view.setLayoutParams(new ViewGroup.LayoutParams(desiredWidth, LayoutParams.WRAP_CONTENT));
view.measure(desiredWidth, MeasureSpec.UNSPECIFIED);
totalHeight += view.getMeasuredHeight();
}
ViewGroup.LayoutParams params = listView.getLayoutParams();
params.height = totalHeight + (listView.getHeight() * (listAdapter.getCount() - 1));
listView.setLayoutParams(params);
listView.requestLayout();
}
Can any one help me out to placed a StaggeredGridView inside a scroll view..
Thanks in advance
Try to use below code with passing no of column :
public void setListViewHeightBasedOnChildren(StaggeredGridView staggeredGridView, int columns) {
SampleAdapter listAdapter = (SampleAdapter) staggeredGridView.getAdapter();
if (listAdapter == null) {
// pre-condition
return;
}
int totalHeight = 0;
int items = listAdapter.getCount();
int rows = 0;
View listItem = listAdapter.getView(0, null, staggeredGridView);
listItem.measure(0, 0);
totalHeight = listItem.getMeasuredHeight();
float x = 1;
if( items > columns ){
x = items/columns;
rows = (int) (x + 1);
totalHeight *= rows;
}
ViewGroup.LayoutParams params = gridView.getLayoutParams();
params.height = totalHeight;
gridView.setLayoutParams(params);
}
I made a class extending ExpandableListView. Following is the code :
class CustomExpandableListView extends ExpandableListView {
public CustomExpandableListView(Context context) {
super(context);
}
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
/*
* Adjust height
*/
heightMeasureSpec = MeasureSpec.makeMeasureSpec(
700, MeasureSpec.AT_MOST);
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
}
}
And I used it as.
ExpandableListView list = new CustomExpandableListView(KaasMain.this);
Adapter adapter = new Adapter(KaasMain.this, objectsLvl1);
list.setAdapter(adapter);
parent.addView(list);
// list.setGroupIndicator();
list.setTranscriptMode(ExpandableListView.TRANSCRIPT_MODE_ALWAYS_SCROLL);
list.setIndicatorBounds(0, 0);
list.setChildIndicatorBounds(0, 0);
I also set its transcript mode TRANSCRIPT_MODE_ALWAYS_SCROLL. But its not scrolling till the end if i clicking on multiple items then the length increases and its hiding end items.
I want something like this:
You need to use these parameters in your list view:
list.setTranscriptMode(ExpandableListView.TRANSCRIPT_MODE_ALWAYS_SCROLL);
Set the head of the list to it bottom
list.setStackFromBottom(true);
You can also set in your xml
android:transcriptMode="alwaysScroll"
Try this:
list.smoothScrollToPosition(list.getCount() - 1);
If need you try to scroll right away after updating the list, see this answer:
How to scroll to the bottom of ListView programmatically?
Step 1: Create Layout Using this:
<ScrollView
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_marginBottom="#dimen/dp10"
android:layout_marginTop="#dimen/toolbar_after_margin"
android:orientation="vertical">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent">
<ExpandableListView
android:id="#+id/expand"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_marginTop="#dimen/dp10"
android:dividerHeight="1dp"
android:indicatorLeft="#dimen/dp20"
android:layoutDirection="rtl" />
</LinearLayout>
</ScrollView>
Step 2:
Create A Function as below
public void setListViewHeight(ExpandableListView listView,
int group,int type) {
ExpandableListAdapter listAdapter = listView.getExpandableListAdapter();
int totalHeight = 0;
int desiredWidth = View.MeasureSpec.makeMeasureSpec(listView.getWidth(),
View.MeasureSpec.EXACTLY);
for (int i = 0; i < listAdapter.getGroupCount(); i++) {
View groupItem = listAdapter.getGroupView(i, false, null, listView);
groupItem.measure(desiredWidth, View.MeasureSpec.UNSPECIFIED);
totalHeight += groupItem.getMeasuredHeight();
if(type!=1){
if (((listView.isGroupExpanded(i)) && (i != group))
|| ((!listView.isGroupExpanded(i)) && (i == group))) {
for (int j = 0; j < listAdapter.getChildrenCount(i); j++) {
View listItem = listAdapter.getChildView(i, j, false, null,
listView);
listItem.measure(desiredWidth, View.MeasureSpec.UNSPECIFIED);
totalHeight += listItem.getMeasuredHeight();
}
}
}
}
ViewGroup.LayoutParams params = listView.getLayoutParams();
int height = totalHeight
+ (listView.getDividerHeight() * (listAdapter.getGroupCount() - 1));
if (height < 10)
height = 200;
params.height = height;
listView.setLayoutParams(params);
listView.requestLayout();
}
Step3: Call setListViewHeight on groupClickListener
elv_categories.setOnGroupClickListener(new ExpandableListView.OnGroupClickListener() {
#Override
public boolean onGroupClick(ExpandableListView parent, View v,
int groupPosition, long id) {
setListViewHeight(parent, groupPosition, 2);
return false;
}
});
}
step4 Call setListViewHeight() after Adapter Set
Categories categories[] = response_data.getCategories();
elv_categories.setAdapter(new ExpandableListAdapter(categories, getApplicationContext()));
setListViewHeight(elv_categories, 0, 1);
I need to change the height of a ListView dynamically in my app.
Is there any way to do that?
This piece of code helped me to achieve dynamic listview height.
import android.view.View;
import android.view.ViewGroup;
import android.view.View.MeasureSpec;
import android.widget.ListAdapter;
import android.widget.ListView;
public class Utility {
public static void setListViewHeightBasedOnChildren(ListView listView) {
ListAdapter listAdapter = listView.getAdapter();
if (listAdapter == null) {
// pre-condition
return;
}
int totalHeight = 0;
int desiredWidth = MeasureSpec.makeMeasureSpec(listView.getWidth(), MeasureSpec.AT_MOST);
for (int i = 0; i < listAdapter.getCount(); i++) {
View listItem = listAdapter.getView(i, null, listView);
listItem.measure(desiredWidth, MeasureSpec.UNSPECIFIED);
totalHeight += listItem.getMeasuredHeight();
}
ViewGroup.LayoutParams params = listView.getLayoutParams();
params.height = totalHeight + (listView.getDividerHeight() * (listAdapter.getCount() - 1));
listView.setLayoutParams(params);
listView.requestLayout();
}
}
In the main Activity use this Utility class to change the listview height.
phraseListView=(ListView)findViewById(R.id.phrase_listview);
phraseAdapter=new PhraseListAdapter(this);
phraseListView.setAdapter(phraseAdapter);
Utility.setListViewHeightBasedOnChildren(phraseListView);
Taken from here
for change height and width dynamically so, try this
RelativeLayout.LayoutParams mParam = new RelativeLayout.LayoutParams((int)(width),(int)(height);
listView.setLayoutParams(mParam);
you can also use LayoutParams.FILL_PARENT or LayoutParams.WRAP_CONTENT instead of height & width
You can use below method to set the height of listview programmatically as per your items:
<ListView
android:id="#+id/lvMenu"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#ffffff"
/>
Method used for setting height of listview:
public static boolean setListViewHeightBasedOnItems(ListView listView) {
ListAdapter listAdapter = listView.getAdapter();
if (listAdapter != null) {
int numberOfItems = listAdapter.getCount();
// Get total height of all items.
int totalItemsHeight = 0;
for (int itemPos = 0; itemPos < numberOfItems; itemPos++) {
View item = listAdapter.getView(itemPos, null, listView);
float px = 500 * (listView.getResources().getDisplayMetrics().density);
item.measure(View.MeasureSpec.makeMeasureSpec((int)px, View.MeasureSpec.AT_MOST), View.MeasureSpec.makeMeasureSpec(0, View.MeasureSpec.UNSPECIFIED));
totalItemsHeight += item.getMeasuredHeight();
}
// Get total height of all item dividers.
int totalDividersHeight = listView.getDividerHeight() *
(numberOfItems - 1);
// Get padding
int totalPadding = listView.getPaddingTop() + listView.getPaddingBottom();
// Set list height.
ViewGroup.LayoutParams params = listView.getLayoutParams();
params.height = totalItemsHeight + totalDividersHeight + totalPadding;
listView.setLayoutParams(params);
listView.requestLayout();
return true;
} else {
return false;
}
}
Then set it like below code:
MenuAdapter menuAdapter = new MenuAdapter(context, R.layout.menu_item);
lvMenu.setAdapter(menuAdapter);
setListViewHeightBasedOnItems(lvMenu);
Hope it will help you.
First thing to keep in mind is that while getting height of listview using mylistview.getmeasureheight, it always gives height according to the textview/View inside the list which was set during initializing of adapter. So we need to declare the adapter as follows:
myadapter = new ArrayAdapter<String>(this,android.R.layout.simple_list_item_1,myarraylist){
#NonNull
#Override
public View getView(int position, #Nullable View convertView, #NonNull ViewGroup parent) {
View view = super.getView(position, convertView, parent);
TextView textView = ((TextView) view.findViewById(android.R.id.text1));
textView.setMinHeight(0); // Min Height
textView.setMinimumHeight(0); // Min Height
textView.setHeight(100); // Height
return view;
}
};
Now height is fixed to 100. Note that it's the height of text and not the view itself. So keep it in mind when adding padding.
Now set the Adapter:
mylist.setAdapter(myadapter);
Now after every time you add an item to your list call a function as follows:
myarraylist.add(ds.getKey());
myadapter.notifyDataSetChanged();
mylist.setAdapter(myadapter);
setListViewHeightBasedOnItems(mylist);
define the function in same class as:
public static boolean setListViewHeightBasedOnItems(ListView listView) {
ListAdapter listAdapter = listView.getAdapter();
if (listAdapter != null) {
int numberOfItems = listAdapter.getCount();
// Get total height of all items.
int totalItemsHeight = 0;
for (int itemPos = 0; itemPos < numberOfItems; itemPos++) {
View item = listAdapter.getView(itemPos, null, listView);
float px = 500 * (listView.getResources().getDisplayMetrics().density);
item.measure(View.MeasureSpec.makeMeasureSpec((int)px, View.MeasureSpec.AT_MOST), View.MeasureSpec.makeMeasureSpec(0, View.MeasureSpec.UNSPECIFIED));
totalItemsHeight += item.getMeasuredHeight();
}
// Get total height of all item dividers.
int totalDividersHeight = listView.getDividerHeight() *
(numberOfItems - 1);
// Get padding
int totalPadding = listView.getPaddingTop() + listView.getPaddingBottom();
// Set list height.
ViewGroup.LayoutParams params = listView.getLayoutParams();
params.height = totalItemsHeight + totalDividersHeight + totalPadding;
listView.setLayoutParams(params);
listView.requestLayout();
return true;
} else {
return false;
}
}
You can also check if height is set or not correctly by returning true/false. This solution worked for me. Hope this Helps!!!!!
You have to create a new control that extends the listview overwhriting some functions
public class WrapContentListView extends ListView {
public WrapContentListView(Context context) {
super(context);
}
public WrapContentListView(Context context, AttributeSet attrs) {
super(context, attrs);
}
public WrapContentListView(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
}
#Override
public void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
int expandSpec = MeasureSpec.makeMeasureSpec(Integer.MAX_VALUE >> 2,
MeasureSpec.AT_MOST);
super.onMeasure(widthMeasureSpec, expandSpec);
}
#Override
public void setAdapter(ListAdapter adapter) {
super.setAdapter(adapter);
setHeightWrapContent();
}
public void setHeightWrapContent() {
ListAdapter listAdapter = getAdapter();
if (listAdapter == null) {
return;
}
int totalHeight = 0;
for (int i = 0; i < listAdapter.getCount(); i++) {
View listItem = listAdapter.getView(i, null, this);
listItem.measure(0, 0);
totalHeight += listItem.getMeasuredHeight();
}
ViewGroup.LayoutParams params = this.getLayoutParams();
params.height = totalHeight
+ (this.getDividerHeight() * (listAdapter.getCount() - 1));
this.setLayoutParams(params);
}
}
https://github.com/mzlogin/WrapContentListView/blob/master/app/src/main/java/org/mazhuang/wrapcontentlistview/WrapContentListView.java
Personaly I spent so much time trying to find a solution, turns out all I had to do is to set my listview's height to wrap_content.
use customized listview and give height as wrap_content.