Reputation: 5743
In my layout I have two ListViews positioned one after another in a vertical LinearLayout like this:
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:orientation="vertical"
android:layout_height="fill_parent">
<ListView android:id="@+id/events_list"
android:layout_width="fill_parent"
android:layout_height="wrap_content"/>
<ListView android:id="@+id/list"
android:layout_width="fill_parent"
android:layout_height="wrap_content"/>
</LinearLayout>
I want to implement for each element in the first ListView onItemClick event, which will expand each row to show additional information.
To achieve this I decided to add all the elements in the initial adapter getView function, but some of them with the "View.GONE" visibility, and then on click I change their visibility to visible.
The problem is that the initial height of the list element does not expand, only scrolling is added.
I am aware of the ExpandableListView, but I never used it and I don't know if it would be the right solutions for this quite simple case.
Excerpt of the layout of the element I'm adding to the first ListView (may be useful):
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:orientation="horizontal"
android:layout_height="wrap_content">
...
</LinealLayout>
Upvotes: 1
Views: 1416
Reputation: 39
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;
}
Upvotes: 0
Reputation: 5743
I ended up using a non-animated technique as in Collapsed List example from android sample apps.
Basically they change a boolean variable in the adapter and re-draw the whole list by sending notifyDatasetChanged()
.
Upvotes: 0
Reputation: 7663
Based on what you're describing I think you need to use an expandable listview. Updating the invividual items in a list is a pain because of how the list view works. ListView
will only initially create as many views as it takes to fill the screen and then recycle those views as the user scrolls the list. Sure you can change the values - e.g. update text fields and pictures - but the view it self is not reinflated every time, only the contents of the child elements changed. This is probably why the height doesn't chane. The Adapter is showing the new child views but doing so within the height of the originaly inflated list item.
One I can think of you getting this to work is by using View.INVISIBLE instead of View.GONE. This way you would inflate a view of the height required to display all the elements and show/hide as someone click. The problem is that this does not achieve the expand/contract state you are looking for. Plus its going to have a ton of ugly white space where things are hidden.
That being said I don't know that setting all these view elements to gone is a good idea. ExpandableListView
is designed such that you can have a regular view and expand a different view on click. This is much more efficient than parsing ever possible XML element for each view and then trying to show/hide different fields onClick. Look into using this method. It's not much harder than regular list view and will much better suit what you're trying to do.
Upvotes: 1