アンドロイド端末のアプリを作成している者です。
仕事で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 List treeEntries = 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 Map expandMap = 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で、コードに色付けしてみました。
返信削除