2011-03-04 1 views
13

ArrayAdapter과 유사하게 작동하는 내 ExpandableListAdapter을 작성하려고합니다. 내 데이터 모델은 다음과 같습니다.사용자 정의 ExpandableListAdapter 작성 방법

public class Group { 

    private String name; 

    private List<Child> children; 
} 

public class Child { 

    private String name; 
} 

아주 간단합니다. 이 관계를 ExpandableListAdapter 구현에 어떻게 매핑 할 수 있습니까? 지금 당장 작동하는 SimpleExpandableListAdapter이 있지만 항목 (아이콘 표시 등)에 대한 사용자 정의 컨트롤이 더 필요합니다. 이 일을 어떻게해야합니까?

가장 중요한 점은 그룹을 추가하고 자식을 추가하고 어댑터에서 제거 할 때 목록을 무효화하려면 add() 메서드가 필요하다는 것입니다. 실제로 SDK를 구현하는 데 도움이되는 SDK (심지어 추상적 인 SDK)의 구현이 없다는 사실에 놀랐습니다.

답변

26

다음은 구현 한 것입니다. 나는 그것이 작동하는지 아닌지 잘 모르지만, 나에게 "현명한"것처럼 보입니다 :) 그런데, 결합 된 자식 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; 
    } 
} 

모든 의견이나 비평을 환영합니다. 이 게시물에 대한 답변이 얼마나 오래된보고

+0

, 그냥이 테스트는 잘 작동하는 것 같다. :) –

+0

그냥 고맙습니다. – myforums

+0

그 자리에서 그것을 채찍질하기보다는 오히려 인상적입니다. –

4

나는 이것에 대한 더 나은 문서를 찾지 못한 것에 상당히 놀랐다. 찾으면 여기에 게시하십시오. 내가 찾은 최고의 구현 예는 ApiDemos에서 발견되었습니다. BaseExpandableListAdapter을 구현하는 ExpandableListActivity이 있습니다. 이 클래스의 이름은 ExpandableList1.java입니다.

GroupChild 클래스를 어댑터에 추가하는 자체 add() 메서드를 만들어야합니다. 언뜻보기에는 그렇게 어려울 것이라고 생각하지 않습니다. 실제로 클래스 객체에 대한 참조를 만들 수 있습니다. 광산을 구현할 때 데이터 세트는 작았고 변경되지 않았으므로 array.xml 파일 만 참조하면됩니다.

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; 
     } 
    } 
1

, 나는 내가 그렇다고이 빠진 틈을 채우고 아주 좋은 3rd party library이 지적 거라 생각 했어요. 게시 된 사용자 정의 솔루션은 좋지만 아직까지는 누락 된 부분이 있으며 프로그래머가 데이터 구조의 데이터 구조를 생성해야한다는 번거로운 설계를 따르고 있습니다. 때로는 하나의 목록을 자신의 일을 처리하는 번거 로움없이 멋진 작은 그룹으로 정리하기를 원할 때가 있습니다.

는 그것은 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); 
    } 
}