前回は、ViewGroup.addView(View, int, ViewGroup.LayoutParams)をオーバーライドすれば動作を変更できそうという調査まで行った。今回は、実際にオーバーライドして動作を確認してみた。
public class HogeViewGroup extends FrameLayout { private SparseArray<SparseArray<Object>> children = new SparseArray<SparseArray<Object>>(); // FrameLayout と同じ引数でコンストラクターを作成 @Override public void addView(View child, int index, ViewGroup.LayoutParams params) { Log.d(Consts.LOG_TAG, "addView(View, int, ViewGroup.LayoutParams), " + "(" + child.getClass().getCanonicalName() + ", " + index + ")"); SparseArray<Object> sa = new SparseArray<Object>(3); sa.put(0, child); sa.put(1, index); sa.put(2, params); children.put(child.getId(), sa); } public void attach(int id) { Log.d(Consts.LOG_TAG, "attach(" + id + ")" + this.getChildCount()); removeAllViews(); SparseArray<Object> sa = children.get(id); super.addView((View) sa.get(0), (Integer) sa.get(1), (LayoutParams) sa.get(2)); } }
Android のフレームワークが addView(View, int, ViewGroup.LayoutParams) メソッドを呼び出したときは SparseArray に格納する。SparseArray への格納方法はもうちょっとスマートに行う必要があると思うが、実験中なのでちょっと適当だ。attach(int)を呼び出すと、表示したい View を実際に addView(View, int, ViewGroup.LayoutParams) するようにしてみた。attach(int)メソッドの引数は、R.id.mainView など、レイアウト XML で指定した ID になる。
動かしてみても特に問題はないので、このまま使えそうな気もするのだが、問題点が2つあった。
- HogeViewGroup のインスタンスを Activity が保持していないと attach(int) メソッドを任意の場所から呼び出せない(もしくは想定していない動きになる)
- attach(int) メソッドを呼び出したときに removeAllViews() メソッドを呼び出すので、子の View で SurfaceView を利用していると遅い
1の方はなんとか回避する方法があるにしても、2の方は「ViewGroup を継承したクラスを自作する」理由が Activity の切り替え速度が気になったことが理由だけに致命的だ。もう少し調整が必要になりそう・・・ちなみに、SurfaceView を利用していないときは、速度はほとんど気になりませんでした。
最終形になるか分からないけど、現在のところ、addView() メソッドで View を追加する際に、enable を false、visibility を INVISIBLE に、attach() にあたるメソッドで、enable を true にして visibility を VISIBLE にしている。