我正在编写自己的ExpandableListAdapter
,其操作方式与ArrayAdapter
类似。我的数据模型是:
public class Group {
private String name;
private List<Child> children;
}
public class Child {
private String name;
}
非常简单。如何将此关系映射到ExpandableListAdapter
实现?我现在正在工作SimpleExpandableListAdapter
,但我需要对项目进行更多自定义控制(显示图标等)。我该怎么办?
主要的是我需要一个add()
方法来添加组,并在添加和从适配器中删除子项时使列表无效。我真的很惊讶SDK中没有实现(甚至是抽象的),这有助于实现这一点。
答案 0 :(得分:26)
这是我刚刚发起的一个实现。我不知道它是否有效,但似乎&#34;聪明&#34;对我来说:)顺便说一下,如何获得组合的子id或组合组ID,所以我只是在那里即兴创作。
package example;
import java.util.ArrayList;
import java.util.List;
import java.util.Map.Entry;
import android.content.Context;
import android.database.DataSetObservable;
import android.database.DataSetObserver;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ExpandableListAdapter;
public abstract class AbstractExpandableListAdapter<A, B> implements ExpandableListAdapter {
private final List<Entry<A, List<B>>> objects;
private final DataSetObservable dataSetObservable = new DataSetObservable();
private final Context context;
private final Integer groupClosedView;
private final Integer groupExpandedView;
private final Integer childView;
private final LayoutInflater inflater;
public AbstractExpandableListAdapter(Context context, int groupClosedView,
int groupExpandedView, int childView, List<Entry<A, List<B>>> objects) {
this.context = context;
this.objects = objects;
this.groupClosedView = new Integer(groupClosedView);
this.groupExpandedView = new Integer(groupExpandedView);
this.childView = new Integer(childView);
this.inflater = (LayoutInflater) this.context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
}
public void add(Entry<A, List<B>> group) {
this.getObjects().add(group);
this.notifyDataSetChanged();
}
public void remove(A group) {
for (Entry<A, List<B>> entry : this.getObjects()) {
if (entry != null && entry.getKey().equals(group)) {
this.getObjects().remove(group);
this.notifyDataSetChanged();
break;
}
}
}
public void remove(Entry<A, List<B>> entry) {
remove(entry.getKey());
}
public void addChild(A group, B child) {
for (Entry<A, List<B>> entry : this.getObjects()) {
if (entry != null && entry.getKey().equals(group)) {
if (entry.getValue() == null)
entry.setValue(new ArrayList<B>());
entry.getValue().add(child);
this.notifyDataSetChanged();
break;
}
}
}
public void removeChild(A group, B child) {
for (Entry<A, List<B>> entry : this.getObjects()) {
if (entry != null && entry.getKey().equals(group)) {
if (entry.getValue() == null)
return;
entry.getValue().remove(child);
this.notifyDataSetChanged();
break;
}
}
}
public void notifyDataSetChanged() {
this.getDataSetObservable().notifyChanged();
}
public void notifyDataSetInvalidated() {
this.getDataSetObservable().notifyInvalidated();
}
public void registerDataSetObserver(DataSetObserver observer) {
this.getDataSetObservable().registerObserver(observer);
}
public void unregisterDataSetObserver(DataSetObserver observer) {
this.getDataSetObservable().unregisterObserver(observer);
}
public int getGroupCount() {
return getObjects().size();
}
public int getChildrenCount(int groupPosition) {
return getObjects().get(groupPosition).getValue().size();
}
public Object getGroup(int groupPosition) {
return getObjects().get(groupPosition).getKey();
}
public Object getChild(int groupPosition, int childPosition) {
return getObjects().get(groupPosition).getValue().get(childPosition);
}
public long getGroupId(int groupPosition) {
return ((Integer)groupPosition).longValue();
}
public long getChildId(int groupPosition, int childPosition) {
return ((Integer)childPosition).longValue();
}
public boolean hasStableIds() {
return true;
}
public View getGroupView(int groupPosition, boolean isExpanded,
View convertView, ViewGroup parent) {
if (convertView != null && convertView.getId() !=
(isExpanded ? getGroupExpandedView() : getGroupClosedView())) {
// do nothing, we're good to go, nothing has changed.
} else {
// something has changed, update.
convertView = inflater.inflate(isExpanded ? getGroupExpandedView() :
getGroupClosedView(), parent, false);
convertView.setTag(getObjects().get(groupPosition));
}
return convertView;
}
public View getChildView(int groupPosition, int childPosition,
boolean isLastChild, View convertView, ViewGroup parent) {
if (convertView != null) {
// do nothing
} else {
// create
convertView = inflater.inflate(getChildView(), parent, false);
convertView.setTag(getObjects().get(groupPosition).getValue().get(childPosition));
}
return convertView;
}
public boolean isChildSelectable(int groupPosition, int childPosition) {
return true;
}
public boolean areAllItemsEnabled() {
return true;
}
public boolean isEmpty() {
return getObjects().size() == 0;
}
public void onGroupExpanded(int groupPosition) {
}
public void onGroupCollapsed(int groupPosition) {
}
public long getCombinedChildId(long groupId, long childId) {
return groupId * 10000L + childId;
}
public long getCombinedGroupId(long groupId) {
return groupId * 10000L;
}
protected DataSetObservable getDataSetObservable() {
return dataSetObservable;
}
protected List<Entry<A, List<B>>> getObjects() {
return objects;
}
protected Context getContext() {
return context;
}
protected Integer getGroupClosedView() {
return groupClosedView;
}
protected Integer getGroupExpandedView() {
return groupExpandedView;
}
protected Integer getChildView() {
return childView;
}
}
欢迎任何评论或批评。
答案 1 :(得分:4)
我很惊讶我没有找到更好的文档。如果您找到,请在此处发布。我发现的最佳实现示例是在ApiDemos中。有ExpandableListActivity
实现了BaseExpandableListAdapter
。该类名为ExpandableList1.java。
您必须创建自己的add()
方法,将Group
和Child
类添加到适配器。我不认为乍一看会那么困难。实际上,您可能只能创建对类对象的引用。当我实现我的时,我的数据集很小并且没有改变所以我只需要引用我的array.xml文件。
答案 2 :(得分:1)
public class CustomExpandableAdapter extends BaseExpandableListAdapter {
private Context mContext;
private List<Group> mData;
private int mSelectedPosition = -1;
public CustomExpandableAdapter(Context context, List<Group> data ) {
mData = data;
mContext = context;
}
@Override
public int getGroupCount() {
return mData.size();
}
@Override
public int getChildrenCount(int groupPosition) {
return mData.get(groupPosition).children.size();
}
@Override
public Object getGroup(int groupPosition) {
return mData.get(groupPosition);
}
@Override
public Object getChild(int groupPosition, int childPosition) {
return mData.get(groupPosition).children.get(childPosition);
}
@Override
public long getGroupId(int groupPosition) {
return groupPosition;
}
@Override
public long getChildId(int groupPosition, int childPosition) {
return childPosition;
}
@Override
public boolean hasStableIds() {
return false;
}
@Override
public View getGroupView(int groupPosition, boolean isExpanded, View convertView, ViewGroup parent) {
HeaderViewHolder headerViewHolder = null;
if (convertView == null) {
convertView = LayoutInflater.from(mContext).inflate(R.layout.faq_header_text_layout, null);
headerViewHolder = new HeaderViewHolder(convertView);
convertView.setTag(headerViewHolder);
}
headerViewHolder = (HeaderViewHolder) convertView.getTag();
headerViewHolder.mGroupHeader.setText(mData.get(groupPosition).name);
return convertView;
}
@Override
public View getChildView(int groupPosition, int childPosition, boolean isLastChild, View convertView, ViewGroup parent) {
ChildViewHolder childViewHolder = null;
if (convertView == null) {
convertView = LayoutInflater.from(mContext).inflate(R.layout.faq_textview_layout, null);
childViewHolder = new ChildViewHolder(convertView);
convertView.setTag(childViewHolder);
}
childViewHolder = (ChildViewHolder) convertView.getTag();
childViewHolder.mChildTitle.setText(mData.get(groupPosition).children.get(childPosition));
return convertView;
}
@Override
public boolean isChildSelectable(int groupPosition, int childPosition) {
return false;
}
private static class HeaderViewHolder {
final TextView mGroupHeader;
private HeaderViewHolder(View group) {
mGroupHeader = (TextView) group.findViewById(R.id.txv_faq_header_text_layout);
}
}
private static class ChildViewHolder {
final TextView mChildTitle;
private ChildViewHolder(View group) {
mChildTitle = (TextView) group.findViewById(R.id.txv_faq_textview_layout);
}
}
@Override
public void unregisterDataSetObserver(DataSetObserver observer) {
if (observer != null) {
super.unregisterDataSetObserver(observer);
}
}
public void setSelectedPosition(int selectedPosition) {
mSelectedPosition = selectedPosition;
}
}
答案 3 :(得分:1)
看到这篇文章和答案有多久,我想我会指出有一个非常好的3rd party library,这种填补了这个缺失的空白。虽然发布的自定义解决方案很好,但它们仍然缺少一些东西,并且正在遵循要求程序员生成数据结构的数据结构的繁琐设计。有时候,你只想把一个List组织成漂亮的小组,而不必自己去做。
它被称为 RolodexArrayAdapter ,可以轻松用于创建自定义 ExpandableListAdapters ...而无需担心所有数据管理问题和功能。它支持add,addAll,remove,removeAll,retainAll,contains,sorting等方法。它还支持更高级的功能,如ChoiceMode,Filtering和自动扩展组。
示例:
class MovieAdapter extends RolodexArrayAdapter<Integer, MovieItem> {
public MovieAdapter(Context activity, List<MovieItem> movies) {
super(activity, movies);
}
@Override
public Integer createGroupFor(MovieItem childItem) {
//Lets organize our movies by their release year
return childItem.year;
}
@Override
public View getChildView(LayoutInflater inflater, int groupPosition, int childPosition,
boolean isLastChild, View convertView, ViewGroup parent) {
if (convertView == null) {
//Inflate your view
}
//Fill view with data
return convertView;
}
@Override
public View getGroupView(LayoutInflater inflater, int groupPosition, boolean isExpanded,
View convertView, ViewGroup parent) {
if (convertView == null) {
//Inflate your view
}
//Fill view with data
return convertView;
}
@Override
public boolean hasAutoExpandingGroups() {
return true;
}
@Override
protected boolean isChildFilteredOut(MovieItem movie, CharSequence constraint) {
//Lets filter by movie title
return !movie.title.toLowerCase(Locale.US).contains(
constraint.toString().toLowerCase(Locale.US));
}
@Override
protected boolean isGroupFilteredOut(Integer year, CharSequence constraint) {
//Lets filter out everything whose year does not match the numeric values in the constraint.
return TextUtils.isDigitsOnly(constraint) && !year.toString().contains(constraint);
}
}