アンドロイド端末のアプリを作成している者です。
仕事でGUIを考えているとき、「ツリー表示ができるビューはないのか!?」と思い探してみました。
GoogleCodeで検索すると出てきたのですが、やはり自分で作ってしまおうと思い作ってみました。
まずはコアとなるアダプタクラスです。(ビュークラスはListViewを使います)
import java.util.ArrayList; import java.util.List; import android.widget.BaseAdapter; public abstract class BaseTreeAdapter extends BaseAdapter { TreeEntry rootEntry = null; public TreeEntry add(Object entry) { if(rootEntry == null) rootEntry = new TreeEntry(); return rootEntry.add(entry); } @Override public int getCount() { return rootEntry == null ? 0 : rootEntry.getCount(); } @Override public Object getItem(int position) { // position=0はrootEntryとなってしまうため // インクリメントする return rootEntry == null ? null : rootEntry.getItem(position + 1) ; } @Override public long getItemId(int position) { //TreeEntry treeEntry = (TreeEntry)getItem(position); //return treeEntry.getId(); return 0; } public class TreeEntry { private ListtreeEntries = null; private int depth = -1; // マイナスはルートオブジェクトのみ private boolean isExpanded = false; private Object data = null; private TreeEntry() { // ルートオブジェクト専用 isExpanded = true; } private TreeEntry(TreeEntry parentEntry, Object data) { if(parentEntry != null) depth = parentEntry.depth + 1; this.data = data; } public TreeEntry add(Object entry) { if(treeEntries == null) treeEntries = new ArrayList (); TreeEntry treeEntry = new TreeEntry(this, entry); treeEntries.add(treeEntry); return treeEntry; } private int getCount() { if(treeEntries == null || !isExpanded) return 0; // 自分の持っているエントリの内、 // 開いている数を返す int count = treeEntries.size(); for(TreeEntry entry : treeEntries) count += entry.getCount(); return count; } private TreeEntry getItem(int position) { if(position == 0) return this; // position=0は自分を返す if(treeEntries == null || !isExpanded) return null; for(int i = 0; position >= 0 && i < treeEntries.size(); ++ i) { TreeEntry entry = treeEntries.get(i); -- position; // 子について、 // エントリが取得できない場合、 // 孫をpositionから引く int count = entry.getCount(); if(count >= position) { // 子以降で必ずアイテムが見つかる return entry.getItem(position); } position -= count; } // ここは、アイテム数より大きなpositionを // 指定された場合のみ return null; } public void expand() { if(!hasChild()) return; // 子を持っていない場合、開けない if(isExpanded) return; isExpanded = true; notifyDataSetChanged(); } public void collapse() { if(!isExpanded) return; isExpanded = false; notifyDataSetChanged(); } public boolean isExpanded() { return isExpanded; } public int getDepth() { return depth; } public Object getData() { return data; } public boolean hasChild() { return treeEntries != null && !treeEntries.isEmpty(); } } }
次に上記アダプタクラスから派生したクラスです。
public class MyTreeAdapter extends BaseTreeAdapter { private LayoutInflater inflater = null; @Override public View getView(int position, View convertView, ViewGroup parent) { if(convertView == null) { if(inflater == null) { inflater = (LayoutInflater)parent.getContext().getSystemService(Context.LAYOUT_INFLATER_SERVICE); } convertView = inflater.inflate(R.layout.entry, null); } TreeEntry treeEntry = (TreeEntry)getItem(position); TextView text = (TextView)convertView.findViewById(R.id.text); Object data = treeEntry.getData(); String str = (String)data; text.setText(str); text.setPadding(treeEntry.getDepth() * 20, text.getPaddingTop(), text.getPaddingRight(), text.getPaddingBottom()); return convertView; } }
最後にアクティビティクラスです。
public class Main extends Activity { private MapexpandMap = new HashMap (); @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.main); final ListView listView = (ListView)findViewById(R.id.list); listView.setOnItemClickListener(new OnItemClickListener() { @Override public void onItemClick(AdapterView parent, View view, int position, long id) { TreeEntry treeEntry = (TreeEntry)parent.getItemAtPosition(position); int depth = treeEntry.getDepth(); if(treeEntry.isExpanded()) { expandMap.remove(depth); treeEntry.collapse(); } else { if(treeEntry.hasChild()) { if(expandMap.containsKey(depth)) { expandMap.get(depth).collapse(); } treeEntry.expand(); expandMap.put(depth, treeEntry); } } } } ); listView.setAdapter(new MyTreeAdapter()); MyTreeAdapter adapter = (MyTreeAdapter)listView.getAdapter(); TreeEntry root = adapter.add("1階層目-1"); TreeEntry days = root.add("2階層目-1"); days = root.add("2階層目-2"); days.add("3階層目-1"); days.add("3階層目-2"); root = adapter.add("1階層目-2"); days = root.add("2階層目-3"); days.add("3階層目-3"); days.add("3階層目-4"); days.add("3階層目-5"); days = root.add("2階層目-4"); days.add("3階層目-6"); days.add("3階層目-7"); days.add("3階層目-8"); days.add("3階層目-9"); } }
実行した画面をキャプチャーしました。
アダプタクラスだけで、できてしまいました。
投稿者:島田
Code Prettifyで、コードに色付けしてみました。
返信削除