2011年5月15日日曜日

Android テーマを動的に設定する

AndroidのテーマはAndroidManifest.xmlに設定する他にもsetThemeでも設定できるようなので試す。

初めから用意されてるテーマは、@android:style/Theme.Blackと@android:style/Theme.Liteの2つ。
テーマは独自に定義できるが、とりあえず今回はあらかじめあるLiteを適用させる。

android developersでsetThemeを見ると下記の注意。
Note that this should be called before any views are instantiated in the Context (for example before calling setContentView(View) or inflate(int, ViewGroup)).
このメソッドはContextにViewがインスタンス化される前(setContentViewとかinflateとかされる前)に呼んでね。おに 大体こんな意味かな。

setContentView前に呼ぶってことはこんな感じかな。
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setTheme(android.R.style.Theme_Light);
        setContentView(R.layout.main);
    }
分かりにくいけど、文字だけテーマが適用されて、読みにくくなっている。背景色はそのまま。

ソース読んでないけど、onCreateで何かしてるんだろうな。と、いうことで、setThemeを前に出してみる。
    @Override
    public void onCreate(Bundle savedInstanceState) {
        setTheme(android.R.style.Theme_Light);
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);
    }
うむ。うまくいきました。

でも、setThemeのこの仕様は少し厄介だな。設定画面でテーマ設定させて戻ってきても、戻った画面にテーマを適用させるのは難しそう。

そこで戻った画面にテーマを適用させたように見せる強引な方法。あまり推奨できない方法。
設定画面いく前にそのときのテーマを変数(before_theme)に入れておく。設定画面ではテーマをSharedPreferencesに設定する。んで、元の画面に戻ってきてテーマが変わっているなら、同じ画面をもう一度startActivityして自身はfinishしてしまう。アニメーションをさせないとテーマが適用されたように見える。
    @Override
    public void onResume() {
        super.onResume();
        String theme = PreferenceManager.getDefaultSharedPreferences(this).getString("theme", "black");
        if (!theme.equals(before_theme)) {
            startActivity(new Intent(this, this.getClass()));
            finish();
        }
    }
onCreateはこんなん。
    @Override
    public void onCreate(Bundle savedInstanceState) {
        String theme = PreferenceManager.getDefaultSharedPreferences(this).getString("theme", "black");
        if (theme.equals("black") {
            setTheme(android.R.style.Theme_Black);
        } else {
            setTheme(android.R.style.Theme_Light);
        }
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);
    }
でも、これはサンプルだからonCreateで何もしてないのでいいけど、実際はもっといろんな処理をする。つまり処理コストがかかる。テーマを適用させるためだけに無理してやることでもないような。