问题
I am using a base adapter to set data in a listview dynamically. I tried to set listview height dynamically. It works perfectly if the textview inside it is single line. However if the textview is multiline, the height is not set properly. The height is set considering single line textview only. How can I set correctly set the height of listview items containing multiline textview. Here's the code:
Fragment code:
ListView mlistNews=(ListView)rootView.findViewById(R.id.news_listView);
mlistNews.setAdapter(new NewsAdapter(getActivity(),params_news));
Utils.setListViewHeightBasedOnItems(mlistNews);
Utility function:
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);
item.measure(View.MeasureSpec.makeMeasureSpec(0, View.MeasureSpec.UNSPECIFIED), 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;
}
}
dashboard_list_news.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="horizontal" android:layout_width="match_parent"
android:layout_height="wrap_content"
android:padding="5dp">
<TextView
android:layout_width="0dp"
android:id="@+id/news_item_text"
android:layout_weight="1"
android:layout_height="wrap_content"
android:layout_gravity="left|center_vertical"
android:layout_marginLeft="5dp"/>
<ImageView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:src="@drawable/chevron"
android:layout_gravity="center_vertical|right"
android:layout_marginLeft="5dp"
android:layout_marginRight="10dp" />
</LinearLayout>
listView:
<ListView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="@drawable/rounded_shape_list"
android:id="@+id/news_listView"
android:paddingTop="5dp"
android:paddingBottom="5dp"
android:divider="#6DCB99"
android:dividerHeight="1dp" />
回答1:
As Teemu mentions you need to constrain the width. Sample code below.
float px = 300 * (listView.getResources().getDisplayMetrics().density);
item.measure(View.MeasureSpec.makeMeasureSpec((int)px, View.MeasureSpec.AT_MOST), View.MeasureSpec.makeMeasureSpec(0, View.MeasureSpec.UNSPECIFIED));
回答2:
Could the problem be this call:
item.measure(View.MeasureSpec.makeMeasureSpec(0, View.MeasureSpec.UNSPECIFIED), View.MeasureSpec.makeMeasureSpec(0, View.MeasureSpec.UNSPECIFIED))
Here you are not constraining the width, so the TextView expands to any width it requires to show all the text in single line. Therefore you will always get the height that equals to single line text? I think you should contrain the width here to what is available from the list view.
回答3:
You can try with this custom listview to avoid listhieght having multiline textview problem
<namespace.epicurio.NestedListView
android:id="@+id/listComments"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:layout_marginBottom="2dp"
android:divider="#000000"
android:dividerHeight="1.0sp">
</namespace.epicurio.NestedListView>
public class NestedListView extends ListView implements OnTouchListener, OnScrollListener {
private int listViewTouchAction;
private static final int MAXIMUM_LIST_ITEMS_VIEWABLE = 99;
public NestedListView(Context context, AttributeSet attrs) {
super(context, attrs);
listViewTouchAction = -1;
setOnScrollListener(this);
setOnTouchListener(this);
}
@Override
public void onScroll(AbsListView view, int firstVisibleItem,
int visibleItemCount, int totalItemCount) {
if (getAdapter() != null && getAdapter().getCount() > MAXIMUM_LIST_ITEMS_VIEWABLE) {
if (listViewTouchAction == MotionEvent.ACTION_MOVE) {
scrollBy(0, -1);
}
}
}
@Override
public void onScrollStateChanged(AbsListView view, int scrollState) {
}
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
int newHeight = 0;
final int heightMode = MeasureSpec.getMode(heightMeasureSpec);
int heightSize = MeasureSpec.getSize(heightMeasureSpec);
if (heightMode != MeasureSpec.EXACTLY) {
ListAdapter listAdapter = getAdapter();
if (listAdapter != null && !listAdapter.isEmpty()) {
int listPosition = 0;
for (listPosition = 0; listPosition < listAdapter.getCount()
&& listPosition < MAXIMUM_LIST_ITEMS_VIEWABLE; listPosition++) {
View listItem = listAdapter.getView(listPosition, null, this);
//now it will not throw a NPE if listItem is a ViewGroup instance
if (listItem instanceof ViewGroup) {
listItem.setLayoutParams(new LayoutParams(
LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT));
}
listItem.measure(widthMeasureSpec, heightMeasureSpec);
newHeight += listItem.getMeasuredHeight();
}
newHeight += getDividerHeight() * listPosition;
}
if ((heightMode == MeasureSpec.AT_MOST) && (newHeight > heightSize)) {
if (newHeight > heightSize) {
newHeight = heightSize;
}
}
} else {
newHeight = getMeasuredHeight();
}
setMeasuredDimension(getMeasuredWidth(), newHeight);
}
@Override
public boolean onTouch(View v, MotionEvent event) {
if (getAdapter() != null && getAdapter().getCount() > MAXIMUM_LIST_ITEMS_VIEWABLE) {
if (listViewTouchAction == MotionEvent.ACTION_MOVE) {
scrollBy(0, 1);
}
}
return false;
}
}
回答4:
Try this code:
listview.post(new Runnable() {
@Override
public void run() {
calculateListHeight(listview.getWidth());
}
});
public void calculateListHeight(int width) {
final ListAdapter adapter = listview.getAdapter();
// Calculate the height of the ListView to display all items
int totalHeight = listview.getPaddingTop() + listview.getPaddingBottom();
for (int i = 0; i < adapter.getCount(); i++) {
View item = adapter.getView(i, null, this);
item.measure(
View.MeasureSpec.makeMeasureSpec(width, MeasureSpec.AT_MOST),
View.MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED)
);
totalHeight += item.getMeasuredHeight();
}
ViewGroup.LayoutParams params = listview.getLayoutParams();
params.height = totalHeight + (listview.getDividerHeight() * (adapter.getCount() - 1));
listview.setLayoutParams(params);
listview.requestLayout();
}
回答5:
for @AlexanderAgeichenko Here is my implementation with @baradas and the Question
int totalItemsHeight = 0;
float px = (customListView.getResources().getDisplayMetrics().density);
totalItemsHeight = (int)px;
Log.d(YOUR_TAG, " datta forloop ... px " + px);
Log.d(YOUR_TAG, " datta forloop ... totalItemsHeight = (int)px= " + totalItemsHeight);
for (int itemPos = 0; itemPos < datta.length(); itemPos++) {
View item = CustomListAdptr.getView(itemPos, null, customListView);
//// item.measure(View.MeasureSpec.makeMeasureSpec(0, View.MeasureSpec.UNSPECIFIED),
//// View.MeasureSpec.makeMeasureSpec(0, View.MeasureSpec.UNSPECIFIED));
item.getMeasuredHeightAndState();
Log.d(YOUR_TAG, " datta forloop item.getHeight() " + item.getHeight());
Log.d(YOUR_TAG, " datta forloop item.getMeasuredHeight() " + item.getMeasuredHeight());
Log.d(YOUR_TAG, " datta forloop item.getMeasuredHeightAndState() " + item.getMeasuredHeightAndState());
int itmHeight = item.getHeight();
Log.d(YOUR_TAG, " datta forloop ... itmHeight " + itmHeight);
item.measure(View.MeasureSpec.makeMeasureSpec((int)px, View.MeasureSpec.AT_MOST),
View.MeasureSpec.makeMeasureSpec(0, View.MeasureSpec.UNSPECIFIED));
totalItemsHeight = item.getMeasuredHeight();
// Log.d(YOUR_TAG, " datta forloop ... item.getMeasuredHeight() " + item.getMeasuredHeight());
Log.d(YOUR_TAG, " datta forloop ... totalItemsHeight=item.getMeasuredHeight() " + totalItemsHeight);
}
Log.d(YOUR_TAG, " datta forloop ... totalItemsHeight == " + totalItemsHeight);
// Get total height of all item dividers.
int totalDividersHeight = customListView.getDividerHeight() *
(numberOfItems - 1);
// Get padding
int totalPadding = customListView.getPaddingTop() + customListView.getPaddingBottom();
// Set list height.
ViewGroup.LayoutParams params = customListView.getLayoutParams();
params.height = totalItemsHeight + totalDividersHeight + totalPadding;
customListView.setLayoutParams(params);
customListView.requestLayout();
customListView.canScrollList(0);
And the out put was
D/YOUR_TAG: onViewCompleted() if(success) setting the list data
D/YOUR_TAG: datta counts 3
D/YOUR_TAG: datta forloop ... px 2.0
D/YOUR_TAG: datta forloop ... totalItemsHeight = (int)px= 2
D/YOUR_TAG: datta forloop item.getMeasuredHeightAndState() 0
D/YOUR_TAG: datta forloop item.getMeasuredHeight() 0
D/YOUR_TAG: datta forloop item.getHeight() 0
D/YOUR_TAG: datta forloop ... itmHeight 0
D/YOUR_TAG: datta forloop ... totalItemsHeight=item.getMeasuredHeight() 1709
D/YOUR_TAG: datta forloop item.getMeasuredHeightAndState() 0
D/YOUR_TAG: datta forloop item.getMeasuredHeight() 0
D/YOUR_TAG: datta forloop item.getHeight() 0
D/YOUR_TAG: datta forloop ... itmHeight 0
D/YOUR_TAG: datta forloop ... totalItemsHeight=item.getMeasuredHeight() 1709
D/YOUR_TAG: datta forloop item.getMeasuredHeightAndState() 0
D/YOUR_TAG: datta forloop item.getMeasuredHeight() 0
D/YOUR_TAG: datta forloop item.getHeight() 0
D/YOUR_TAG: datta forloop ... itmHeight 0
D/YOUR_TAG: datta forloop ... totalItemsHeight=item.getMeasuredHeight() 1709
D/YOUR_TAG: datta forloop ... totalItemsHeight == 1709
D/YOUR_TAG: getView() -> unit_option= 0 :: class java.lang.String
WITH 110 float px = 110 *(customListView.getResources().getDisplayMetrics().density);
D/YOUR_TAG: onViewCompleted() if(success) setting the list data
D/YOUR_TAG: datta counts 3
D/YOUR_TAG: datta forloop ... px 220.0
D/YOUR_TAG: datta forloop ... totalItemsHeight = (int)px= 220
D/YOUR_TAG: datta forloop item.getMeasuredHeightAndState() 0
D/YOUR_TAG: datta forloop item.getMeasuredHeight() 0
D/YOUR_TAG: datta forloop item.getHeight() 0
D/YOUR_TAG: datta forloop ... itmHeight 0
D/YOUR_TAG: datta forloop ... totalItemsHeight=item.getMeasuredHeight() 159
D/YOUR_TAG: datta forloop item.getMeasuredHeightAndState() 0
D/YOUR_TAG: datta forloop item.getMeasuredHeight() 0
D/YOUR_TAG: datta forloop item.getHeight() 0
D/YOUR_TAG: datta forloop ... itmHeight 0
D/YOUR_TAG: datta forloop ... totalItemsHeight=item.getMeasuredHeight() 159
D/YOUR_TAG: datta forloop item.getMeasuredHeightAndState() 0
D/YOUR_TAG: datta forloop item.getMeasuredHeight() 0
D/YOUR_TAG: datta forloop item.getHeight() 0
D/YOUR_TAG: datta forloop ... itmHeight 0
D/YOUR_TAG: datta forloop ... totalItemsHeight=item.getMeasuredHeight() 159
D/YOUR_TAG: datta forloop ... totalItemsHeight == 159
来源:https://stackoverflow.com/questions/29225539/set-listview-height-dynamically-based-on-multiline-textview-inside-it