標題雖提及「JavaMail QQ 郵件設定」,但實際內容為 Android ExpandableListView 雙層可展開列表 的完整範例。本文整理關鍵實作步驟與程式碼架構,供快速參考。
<LinearLayout xmlns:android="https://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
android:background="#FFFFFF">
<ExpandableListView
android:id="@+id/elv_journal_catalog"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:cacheColorHint="#FFFFFF" />
</LinearLayout>
public class CatalogActivity extends Activity {
private ExpandableListView elv;
private List<List<Article>> childrenData;
private JournalCatalogListAdapter adapter;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.journal_catalog);
initView();
loadData();
}
private void initView() {
elv = findViewById(R.id.elv_journal_catalog);
elv.setGroupIndicator(null); // 隱藏預設展開圖示
elv.setDivider(null); // 移除分隔線
elv.setOnChildClickListener(listener);
}
private void loadData() {
// 非同步載入資料(略),完成後:
adapter = new JournalCatalogListAdapter(this, childrenData);
elv.setAdapter(adapter);
// 若需預設展開某群組:
// elv.expandGroup(groupPosition);
}
}
關鍵方法說明:
getGroupCount() / getChildrenCount(groupPosition):回傳群組數與子項數。getGroupView() / getChildView():分別渲染群組列與子項列,建議使用 ViewHolder 模式複用 convertView。hasStableIds() 回傳 true 可提升效能。public class JournalCatalogListAdapter extends BaseExpandableListAdapter {
private final LayoutInflater inflater;
private final String[] groupTitles = {"美顏美體", "潮流單品", "娛樂八卦", "情感", "觀點", "健康生活"};
private final List<List<Article>> children;
public JournalCatalogListAdapter(Context context, List<List<Article>> children) {
this.children = children;
this.inflater = LayoutInflater.from(context);
}
@Override public int getGroupCount() { return groupTitles.length; }
@Override public int getChildrenCount(int groupPosition) { return children.get(groupPosition).size(); }
@Override public Object getGroup(int groupPosition) { return groupTitles[groupPosition]; }
@Override public Object getChild(int groupPosition, int childPosition) { return children.get(groupPosition).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 true; }
@Override public boolean isChildSelectable(int groupPosition, int childPosition) { return true; }
@Override
public View getGroupView(int groupPosition, boolean isExpanded, View convertView, ViewGroup parent) {
GroupHolder holder;
if (convertView == null) {
convertView = inflater.inflate(R.layout.journal_catalog_list_item_title, parent, false);
holder = new GroupHolder(convertView);
convertView.setTag(holder);
} else {
holder = (GroupHolder) convertView.getTag();
}
holder.title.setText(getGroup(groupPosition).toString());
return convertView;
}
@Override
public View getChildView(int groupPosition, int childPosition, boolean isLastChild, View convertView, ViewGroup parent) {
ChildHolder holder;
if (convertView == null) {
convertView = inflater.inflate(R.layout.journal_catalog_list_item_content, parent, false);
holder = new ChildHolder(convertView);
convertView.setTag(holder);
} else {
holder = (ChildHolder) convertView.getTag();
}
Article article = (Article) getChild(groupPosition, childPosition);
holder.title.setText(article.getTitle());
return convertView;
}
static class GroupHolder { TextView title; GroupHolder(View v) { title = v.findViewById(R.id.tv_journal_catalog_list_item_title); } }
static class ChildHolder { TextView title; ChildHolder(View v) { title = v.findViewById(R.id.tv_journal_catalog_list_item_content); } }
}
setGroupIndicator(null) 或 setGroupIndicator(Drawable)。expandGroup(position)。childrenData 後呼叫 adapter.notifyDataSetChanged()。