ListView를 만들고 나니까 이번엔 ListView 안에 또 다른 ListView를 만들 필요가 생겼다. ListView 안에 객체로 다른 ListView를 선언해야 하나 하고 다시 여기저기 자료를 찾아봤는데(Google 만세!) 굳이 ListView를 두 번 선언하지 않고도 ExpandableListView라는 class를 이용하여 ParentList, ChildList 식으로 구성하면 되었다. 다만 Android Studio의 자동 완성 기능을 활용해 보니, ExpandableListViewAdapter의 Customizing이 필요했다.
1. 목적 : ExpandableListView의 기본 구조 및 사용법을 알아보자.
2. 개발 환경
- PC : Windows 7, Android Studio 1.4.1(64-bit)
- Phone : LG G pro Lollipop(API 21)
3. 참고자료
1) Android Hive - Android Expandable List View Tutorial (http://www.androidhive.info/2013/07/android-expandable-list-view-tutorial/)
2) 아라비안나이트 블로그 - ExpandableListView 제작 예시(http://arabiannight.tistory.com/entry/%EC%95%88%EB%93%9C%EB%A1%9C%EC%9D%B4%EB%93%9CAndroid-ExpandableListView-%EB%A7%8C%EB%93%A4%EA%B8%B0)
4. 과정
1) activity_main.xml(App에 보여질 전체적인 Layout)에 ExpandableListView를 정의하고, ExpandableListView의 ParentList와 ChildList에 해당하는 list의 객체들을 각각 parent_listview.xml과 child_listview.xml로 다음과 같이 정의한다. 이 때, .xml 파일명의 사용자의 편의에 따라 다르게 쓸 수 있고 .java 에서 연결할 때 해당 .xml 파일명을 적용하면 된다.
| |||
[xml Code] ExpandableListView에서 ParentListView에 해당하는 'parent_listview.xml'을 통해 parent는 각 원소별로 1개의 TextView로 이루어지게 설계했음을 알 수 있으며, ParentList의 원소를 선택했을 경우 나타날 ChildListView는 'child_listview.xml'에서 보이는 바와 같이 1개의 ImageView와 1개의 TextView로 구성되도록 설계했다. |
|
2) 1)의 ExpandableListView가 적용될 CustomAdapter를 다음과 같이 정의한다. 상속받은 method를 @Override 해야함을 잊으면 안된다. 그리고 아래 보기에서 나는 생성자를 통해서 받는 childList를 HashMap 변수를 통해서 연결했지만, 다른 참고자료에서 처럼 List<>등으로 바꾸어 입맛에 맞게 편집하면 된다.
public class CustomExpandableListViewAdapter extends BaseExpandableListAdapter {
private Context mContext;
private ArrayList<String> mParentList;
private ArrayList<ChildListData> mChildList;
private ChildListViewHolder mChildListViewHolder;
private HashMap<String, ArrayList<ChildListData>> mChildHashMap;
// CustomExpandableListViewAdapter 생성자
public CustomExpandableListViewAdapter(Context context, ArrayList<String> parentList, HashMap<String, ArrayList<ChildListData>> childHashMap){
this.mContext = context;
this.mParentList = parentList;
this.mChildHashMap = childHashMap;
}
/* ParentListView에 대한 method */
@Override
public String getGroup(int groupPosition) { // ParentList의 position을 받아 해당 TextView에 반영될 String을 반환
return mParentList.get(groupPosition);
}
@Override
public int getGroupCount() { // ParentList의 원소 개수를 반환
return mParentList.size();
}
@Override
public long getGroupId(int groupPosition) { // ParentList의 position을 받아 long값으로 반환
return groupPosition;
}
@Override
public View getGroupView(int groupPosition, boolean isExpanded, View convertView, ViewGroup parent) { // ParentList의 View
if(convertView == null){
LayoutInflater groupInfla = (LayoutInflater) this.mContext.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
// ParentList의 layout 연결. root로 argument 중 parent를 받으며 root로 고정하지는 않음
convertView = groupInfla.inflate(R.layout.parent_listview, parent, false);
}
// ParentList의 Layout 연결 후, 해당 layout 내 TextView를 연결
TextView parentText = (TextView)convertView.findViewById(R.id.parenttext);
parentText.setText(getGroup(groupPosition));
return convertView;
}
/* 여기서부터 ChildListView에 대한 method */
@Override
public ChildListData getChild(int groupPosition, int childPosition) { // groupPostion과 childPosition을 통해 childList의 원소를 얻어옴
return this.mChildHashMap.get(this.mParentList.get(groupPosition)).get(childPosition);
}
@Override
public int getChildrenCount(int groupPosition) { // ChildList의 크기를 int 형으로 반환
return this.mChildHashMap.get(this.mParentList.get(groupPosition)).size();
}
@Override
public long getChildId(int groupPosition, int childPosition) { // ChildList의 ID로 long 형 값을 반환
return childPosition;
}
@Override
public View getChildView(int groupPosition, int childPosition, boolean isLastChild, View convertView, ViewGroup parent) {
// ChildList의 View. 위 ParentList의 View를 얻을 때와 비슷하게 Layout 연결 후, layout 내 TextView, ImageView를 연결
ChildListData childData = (ChildListData)getChild(groupPosition, childPosition);
if(convertView == null){
LayoutInflater childInfla = (LayoutInflater) this.mContext.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
convertView = childInfla.inflate(R.layout.child_listview, null);
mChildListViewHolder = new ChildListViewHolder();
mChildListViewHolder.mChildListViewIcon = (ImageView)convertView.findViewById(R.id.child_item_icon);
mChildListViewHolder.mChildListViewText = (TextView)convertView.findViewById(R.id.childtext);
convertView.setTag(mChildListViewHolder);
} else{
mChildListViewHolder = (ChildListViewHolder)convertView.getTag();
}
mChildListViewHolder.mChildListViewText.setText(getChild(groupPosition, childPosition).mChildText);
mChildListViewHolder.mChildListViewIcon.setImageDrawable(getChild(groupPosition, childPosition).mChildItem);
return convertView;
}
@Override
public boolean hasStableIds() { return true; } // stable ID인지 boolean 값으로 반환
@Override
public boolean isChildSelectable(int groupPosition, int childPosition) { return true; } // 선택여부를 boolean 값으로 반환
}
3) MainActivity.java(ExpandableListView에 객체를 입력하고 동작에 대한 code 작성)을 다음과 같이 coding한다.
public ExpandableListView expandableListView; // ExpandableListView 변수 선언
public CustomExpandableListViewAdapter mCustomExpListViewAdapter; // 위 ExpandableListView를 받을 CustomAdapter(2번 class에 해당)를 선언
public ArrayList<String> parentList; // ExpandableListView의 Parent 항목이 될 List 변수 선언
public ArrayList<ChildListData> fruit; // ExpandableListView의 Child 항목이 될 List를 각각 선언
public ArrayList<ChildListData> vegetables;
public ArrayList<ChildListData> etc;
public HashMap<String, ArrayList<ChildListData>> childList; // 위 ParentList와 ChildList를 연결할 HashMap 변수 선언
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main); // activity_main.xml을 MainActivity에 연결
// ExpandableListView의 ParentList에 해당할 항목을 입력
parentList = new ArrayList<String>();
parentList.add("과일");
parentList.add("채소");
parentList.add("기타");
// 앞서 ParentList에 연결할 ChildList 항목을 선언 및 입력
ChildListData apple = new ChildListData(getResources().getDrawable(R.mipmap.apple), "사과");
ChildListData pair = new ChildListData(getResources().getDrawable(R.mipmap.pair), "배");
ChildListData persimmon = new ChildListData(getResources().getDrawable(R.mipmap.persimmon), "감");
fruit = new ArrayList<ChildListData>();
fruit.add(apple);
fruit.add(pair);
fruit.add(persimmon);
ChildListData onion = new ChildListData(getResources().getDrawable(R.mipmap.onion), "양파");
ChildListData cabbage = new ChildListData(getResources().getDrawable(R.mipmap.cabbage), "양배추");
ChildListData potato = new ChildListData(getResources().getDrawable(R.mipmap.potato), "감자");
ChildListData sweetPotato = new ChildListData(getResources().getDrawable(R.mipmap.sweetpotato), "고구마");
ChildListData pumpkin = new ChildListData(getResources().getDrawable(R.mipmap.pumpkin), "호박");
vegetables = new ArrayList<ChildListData>();
vegetables.add(onion);
vegetables.add(cabbage);
vegetables.add(potato);
vegetables.add(sweetPotato);
vegetables.add(pumpkin);
ChildListData seaweed = new ChildListData(getResources().getDrawable(R.mipmap.seaweed), "미역");
ChildListData bread = new ChildListData(getResources().getDrawable(R.mipmap.bread), "빵");
ChildListData mackerel = new ChildListData(getResources().getDrawable(R.mipmap.mackerel), "고등어");
etc = new ArrayList<ChildListData>();
etc.add(seaweed);
etc.add(bread);
etc.add(mackerel);
// 위에서 선언한 ParentList와 ChildList를 HashMap을 통해
childList = new HashMap<String, ArrayList<ChildListData>>();
childList.put(parentList.get(0), fruit);
childList.put(parentList.get(1), vegetables);
childList.put(parentList.get(2), etc);
// 앞서 정의해 놓은 ExpandableListView와 그 CustomAdapter를 선언 및 연결한 후
// ExpandableListView에 대한 OnClickListener 등을 선언
expandableListView = (ExpandableListView)findViewById(R.id.expandablelist);
mCustomExpListViewAdapter = new CustomExpandableListViewAdapter(this, parentList, childList);
expandableListView.setAdapter(mCustomExpListViewAdapter);
expandableListView.setOnGroupExpandListener(new ExpandableListView.OnGroupExpandListener() {
@Override
public void onGroupExpand(int groupPosition) {
}
});
expandableListView.setOnGroupCollapseListener(new ExpandableListView.OnGroupCollapseListener() {
@Override
public void onGroupCollapse(int groupPosition) {
}
});
expandableListView.setOnChildClickListener(new ExpandableListView.OnChildClickListener() {
@Override
public boolean onChildClick(ExpandableListView parent, View v, int groupPosition, int childPosition, long id) {
return false;
}
});
}
}
(위 Code의 실행 결과)
'개발일지' 카테고리의 다른 글
[Android 기초] PopupWindow 활용하기 (0) | 2015.12.07 |
---|---|
[Android 기초] 특정 Directory 내 Image들에 대한 gallery 만들기 - Gallery 사용 (5) | 2015.12.04 |
[Android 기초] App에서 기본적으로 사용한 image asset 추가 (0) | 2015.11.30 |
[Android 기초] ListView의 구조 및 예제 02 - Customizing 해보기 (0) | 2015.11.30 |
[Android 기초] ListView의 구조 및 예제 01 - 기초 (0) | 2015.11.30 |