Reputation: 201
I have listView within scrollView (yes, I know thats bad approach. Better to use headers/footers). I know that scrollView and listView have both scroll and that causes some conflict. In this case I need to set height of list manually. And thats the problem since listView has custom adapter.
Layout:
<?xml version="1.0" encoding="utf-8"?>
<ScrollView xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/ScrollView01"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:fillViewport="true"
android:scrollbars="none" >
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent">
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/fragment_lessons"
android:background="#FAF9F9"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context="com.cbsystematic.mobile.itvdn.LessonsFragment">
<TextView
android:id="@+id/course_title"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:text="Описание курса: "
android:textSize="16sp"
android:textStyle="bold"
android:textColor="#000000"/>
<TextView
android:id="@+id/course_description"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:textSize="16sp"
android:layout_below="@id/course_title"
android:textColor="#000000"/>
<TextView
android:id="@+id/course_duration"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:textSize="14sp"
android:textStyle="italic"
android:layout_below="@id/course_description"
android:textColor="#000000"/>
<ListView android:id="@android:id/list"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_below="@id/course_duration"/>
</RelativeLayout>
</LinearLayout>
</ScrollView>
Custom List adapter:
class LessonsItemAdapter extends ArrayAdapter<LessonData> {
private Activity myContext;
private ArrayList<LessonData> datas;
public LessonsItemAdapter(Context context, int textViewResourceId, ArrayList<LessonData> objects){
super(context, textViewResourceId, objects);
myContext = (Activity) context;
datas = objects;
}
public View getView(int position, View convertView, ViewGroup parent){
ViewHolder viewHolder;
if(convertView == null) {
LayoutInflater inflater = myContext.getLayoutInflater();
convertView = inflater.inflate(R.layout.lessons_list_item, null);
viewHolder = new ViewHolder();
viewHolder.postNameView = (TextView) convertView.findViewById(R.id.lessons_name);
viewHolder.postDurationView = (TextView) convertView.findViewById(R.id.lessons_duration);
convertView.setTag(viewHolder);
} else {
viewHolder = (ViewHolder) convertView.getTag();
}
//(position + 1) + ") " used to display 1) 2) 3) etc of lessons
viewHolder.postNameView.setText((position + 1) + ") " + datas.get(position).getName());
viewHolder.postDurationView.setText("Длительность: " + datas.get(position).getDuration().substring(0,8));
return convertView;
}
static class ViewHolder{
TextView postNameView;
TextView postDurationView;
}
}
Method of finding height:
public static void setListViewSize(AbsListView listView) {
ListAdapter listAdapter = 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, AbsListView.LayoutParams.WRAP_CONTENT));
view.measure(desiredWidth, MeasureSpec.UNSPECIFIED);
totalHeight += view.getMeasuredHeight();
}
ViewGroup.LayoutParams params = listView.getLayoutParams();
params.height = totalHeight + (listView.getMeasuredHeight() * (listAdapter.getCount() + 1));
listView.setLayoutParams(params);
listView.requestLayout();
}
Thats how I set the content of list:
mAdapter = new LessonsItemAdapter(getActivity(),
R.layout.lessons_list_item, parserJson.getLessons(courseUrl).getLessonsArray());
// Set the adapter
mListView = (AbsListView) view.findViewById(android.R.id.list);
((AdapterView<ListAdapter>) mListView).setAdapter(mAdapter);
// Set OnItemClickListener so we can be notified on item clicks
mListView.setOnItemClickListener(this);
ListHelper.setListViewSize(mListView);
And thats the result:
The entire View is scrolling. But the last item always shows only by half. You see, the field Duration ("Длительность") is not showing. Although the last item of list is clicakble.
Please help me with that method of defining the total height. Thanks in advance. Appreciate any help.
Upvotes: 1
Views: 2423
Reputation: 573
Your ListView in your layout file should be like
<ListView android:id="@android:id/list"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_below="@id/course_duration"/>
Now in your code where you want the ListView's height to be adjusted according to its children place the following method.
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);
}
just call it by passing your ListView inside it
setListViewHeightBasedOnChildren(list);
Simple but powerful solution
Upvotes: 1
Reputation: 2123
try code below from this blog
@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);
}
Upvotes: 0
Reputation: 1705
Use this piece of code. It will reset the size of listview according to number of items.
public static void setListViewHeightBasedOnChildren(ListView listView) {
ListAdapter listAdapter = 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.getDividerHeight() * (listAdapter.getCount() - 1));
listView.setLayoutParams(params);
listView.requestLayout();
}
Upvotes: 1