How do I use ResourceCursorTreeAdapter with expanded and collapsed group views in Android?
How do I use the ResourceCursorTreeAdapter with the following constructor?
ResourceCursorTreeAdapter(Context context, Cursor cursor, int collapsedGroupLayout, int expandedGroupLayout, int childLayout)
I'm trying to use a it as follows:
_resultsCursorTreeAdapter = new ResourceCursorTreeAdapter(_resultsList.getContext(), _dbAdapter.getAllGroups(),
R.layout.timing_group_view_collapsed, R.layout.timing_group_view_expanded, R.layout.timing_result_view) {
@Override
protected Cursor getChildrenCursor(Cursor groupCursor) {
// Given the group, we return a cursor for all the children within that group
int groupId = groupCursor.getInt(0);
Cursor childCursor = _dbAdapter.getContractionsForGroup(groupId);
return childCursor;
}
@Override
protected void bindGroupView(View groupView, Context context, Cursor cursor,
boolean isExpanded) {
TimingGroupView timingGroupItem = null;
if(groupView instanceof LinearLayout){
Log.i("TimingGroupView", "Has Header");
LinearLayout layout = (LinearLayout)groupView;
timingGroupItem = (TimingGroupView) layout.getChildAt(0);
} else{
Log.i("TimingGroupView", "No Header");
timingGroupItem = (TimingGroupView) groupView;
}
...
If the group node is expanded, I want the group node to include the header for a table which each row is held in a child node. timing_group_view_expanded.xml and timing_group_view_collapsed.xml are shown at the bottom of this question. For some reason, the group_view_expanded is never used whether the group nodes are expanded or collapsed. Am I using this wrong? Has anyone else been able to get ResourceCursorTreeAdapter with this constructor to work?
timing_group_view_expanded.xml is as follows:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout android:id="@+id/timing_group_view"
android:orientation="vertical" android:layout_width="fill_parent"
android:layout_height="wrap_content" xmlns:android="http://schemas.android.com/apk/res/android"
android:background=开发者_开发问答"@color/header_timing_color">
<com.contractiontracker.TimingGroupView
android:id="@+id/timing_group_item" xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent" android:layout_height="wrap_content"
android:layout_marginLeft="30px" android:padding="10dp"
android:scrollbars="vertical"
android:fadingEdge="vertical"
android:background="@color/header_timing_color"
android:textColor="@color/text_color"/>
<com.contractiontracker.RowLayout android:id="@+id/timing_group_view"
android:orientation="horizontal" android:layout_width="fill_parent"
android:layout_height="wrap_content" xmlns:android="http://schemas.android.com/apk/res/android"
android:background="@color/header_color" android:textColor="@color/text_color">
<TextView android:id="@+id/interval_header"
android:layout_width="fill_parent" android:layout_height="wrap_content"
android:text="Interval" android:layout_weight="1"
android:layout_gravity="left|bottom" android:gravity="center"
android:textColor="@color/text_color">
</TextView>
<TextView android:id="@+id/duration_header"
android:layout_width="fill_parent" android:layout_height="wrap_content"
android:text="Duration" android:layout_weight="1"
android:layout_gravity="center_horizontal|bottom" android:gravity="center"
android:textColor="@color/text_color"
>
</TextView>
<TextView android:id="@+id/intensity_header"
android:layout_width="fill_parent" android:layout_height="wrap_content"
android:text="Intensity" android:layout_weight="1"
android:layout_gravity="right|bottom" android:gravity="center"
android:textColor="@color/text_color"
>
</TextView>
</com.contractiontracker.RowLayout>
</LinearLayout>
timing_group_view_collapsed.xml looks like the following:
<?xml version="1.0" encoding="utf-8"?>
<com.contractiontracker.TimingGroupView
android:id="@+id/timing_group_item"
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:layout_marginLeft="50px"
android:padding="10dp"
android:scrollbars="vertical"
android:textColor="@color/text_color"
android:fadingEdge="vertical"/>
The problem is that ResourceCursorTreeAdapter
only creates the correct layouts on creation of a view. So if a group gets collapsed or expanded the newGroupView()
is not called again and therefore the different group layouts passed into the constructor are not used as expected.
Same problem exists with the child layouts when using different ones for normal and last child. It happens there without even changing the data! After re-expanding a group the first one had the footer layout and vice-versa. Totally random and not based on position in the list.
As Aleksander O showed in his example, one can fix this by always call newGroupView()
in the getGroupView
method (and the getChildView
respectively if different layouts are used for that).
To avoid always create new views, I tried a different approach that works for my case:
- Add different ids to the root element of the layouts used for group/child views
Store those view-ids as int members of my Adapter:
// Get the view ids for comparison View view = newGroupView(mContext, null, false, null); mCollapsedGroupLayoutViewId = view.getId(); view = newGroupView(mContext, null, true, null); mExpandedGroupLayoutViewId = view.getId(); view = newChildView(mContext, null, false, null); mChildLayoutViewId = view.getId(); view = newChildView(mContext, null, true, null); mLastChildLayoutViewId = view.getId();
Implementation of getGroupView (and analog with getChildView):
public View getGroupView(int groupPosition, boolean isExpanded, View convertView, ViewGroup parent) { Cursor cursor = getGroup(groupPosition); if (cursor == null) { throw new IllegalStateException("this should only be called when the cursor is valid"); } View v; if (convertView == null || (isExpanded && convertView.getId() == mCollapsedGroupLayoutViewId) || (!isExpanded && convertView.getId() == mExpandedGroupLayoutViewId)) { v = newGroupView(mContext, cursor, isExpanded, parent); } else { v = convertView; } bindGroupView(v, mContext, cursor, isExpanded); return v; }
Here's my temporary solution for SimpleExpandableListAdapter:
public class LocalAdapter extends SimpleExpandableListAdapter {
private List<? extends Map<String, ?>> mGroupData;
private String[] mGroupFrom;
private int[] mGroupTo;
private List<? extends List<? extends Map<String, ?>>> mChildData;
private LayoutInflater mInflater;
public LocalAdapter(Context context,
List<? extends Map<String, ?>> groupData, int groupLayout,
String[] groupFrom, int[] groupTo,
List<? extends List<? extends Map<String, ?>>> childData,
int childLayout, String[] childFrom, int[] childTo) {
this(context, groupData, groupLayout, groupLayout, groupFrom, groupTo, childData,
childLayout, childLayout, childFrom, childTo);
}
public LocalAdapter(Context context,
List<? extends Map<String, ?>> groupData, int expandedGroupLayout,
int collapsedGroupLayout, String[] groupFrom, int[] groupTo,
List<? extends List<? extends Map<String, ?>>> childData,
int childLayout, String[] childFrom, int[] childTo) {
this(context, groupData, expandedGroupLayout, collapsedGroupLayout,
groupFrom, groupTo, childData, childLayout, childLayout,
childFrom, childTo);
}
public LocalAdapter(Context context,
List<? extends Map<String, ?>> groupData, int expandedGroupLayout,
int collapsedGroupLayout, String[] groupFrom, int[] groupTo,
List<? extends List<? extends Map<String, ?>>> childData,
int childLayout, int lastChildLayout, String[] childFrom,
int[] childTo) {
super(context, groupData, expandedGroupLayout,
collapsedGroupLayout, groupFrom, groupTo, childData,
childLayout, lastChildLayout, childFrom, childTo);
mGroupData = groupData;
mGroupFrom = groupFrom;
mGroupTo = groupTo;
mChildData = childData;
mInflater = (LayoutInflater)context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
}
private void bindView(View view, Map<String, ?> data, String[] from, int[] to) {
int len = to.length;
for (int i = 0; i < len; i++) {
TextView v = (TextView)view.findViewById(to[i]);
if (v != null) {
v.setText((String)data.get(from[i]));
}
}
}
@Override
public View getGroupView(int groupPosition, boolean isExpanded, View convertView,
ViewGroup parent) {
View v = newGroupView(isExpanded, parent);
bindView(v, mGroupData.get(groupPosition), mGroupFrom, mGroupTo);
return v;
}
}
Easy solution with good recycling.
@Override
public View getGroupView(int groupPosition, boolean isExpanded, View convertView, ViewGroup parent) {
Cursor cursor = getGroup(groupPosition);
if (cursor == null) {
throw new IllegalStateException("this should only be called when the cursor is valid");
}
View view;
if (convertView == null || convertView.getTag() != isExpanded) {
view = newGroupView(mActivity, cursor, isExpanded, parent);
view.setTag(isExpanded);
} else {
view = convertView;
}
bindGroupView(view, mActivity, cursor, isExpanded);
return view;
}
精彩评论