2010年8月20日金曜日

Android Menu の背景を変える

Menu を作る方法は http://developer.android.com/guide/topics/ui/menus.html
などに書いてありますが、まっとうな方法では、アイコンとタイトルしか
変更できません。

*Menuとはメニューキーを押したときに下から”にゅっ”と出てくる
やつです。



↑これの「使い方」とか「ネイル・ド・ロンジョについて」とかのパネルの部分


システムとの一貫性を保つためにそうなっているんだろうとは
思うのですが、アイコンにすごくカラフルなのとか使ったら
一貫性もなにもないだろぅ。とか思ったりもします。

例えば、ic_menu_**.png はアイコンが灰色ですが、このアイコンの
色を変えた画像を用意して、アイコンに指定すると



となって、メニューパネルの背景色がアプリ全体の色バランスと
合ってない感じになってしまいます。

そこで、メニューパネル部分の背景を変えてみました。






以下やりかたです。

*注! この方法は Reflection で内部クラスを使っているので、SDKのアップデートなどで使えなくなる可能性があります。

  1. import java.lang.reflect.Constructor;  
  2. import java.lang.reflect.InvocationTargetException;  
  3.   
  4. import android.app.Activity;  
  5. import android.content.Context;  
  6. import android.content.Intent;  
  7. import android.graphics.Color;  
  8. import android.os.Bundle;  
  9. import android.util.AttributeSet;  
  10. import android.view.LayoutInflater;  
  11. import android.view.Menu;  
  12. import android.view.MenuInflater;  
  13. import android.view.MenuItem;  
  14. import android.view.View;  
  15. import android.view.ViewGroup;  
  16. import android.view.LayoutInflater.Factory;  
  17.   
  18. public class MenuTest extends Activity {  
  19.   
  20. @Override  
  21. public void onCreate(Bundle savedInstanceState) {  
  22.     super.onCreate(savedInstanceState);  
  23.   
  24.     // ここで設定   
  25.     ensureInflaterFactory();  
  26.           
  27.     setContentView(R.layout.main);  
  28. }  
  29.   
  30.   
  31. void ensureInflaterFactory() {  
  32.     LayoutInflater service = (LayoutInflater) getSystemService(LAYOUT_INFLATER_SERVICE);  
  33.     final Factory orgFactory = service.getFactory();  
  34.   
  35.     if (orgFactory == null) {  
  36.         // View をインスタンス化するための Factory オブジェクトを LayoutInflater に設定する。  
  37.         // Factory の onCreateView で View のインスタンスを return すればそれが使われる。  
  38.         // null を return すれば LayoutInflater 自身がViewをインスタンス化する。  
  39.         final Factory factory = new Factory() {  
  40.             public View onCreateView(String name, Context context, AttributeSet attrs) {  
  41.   
  42.             // メニューパネル部分の内部クラスだけ変更  
  43.             if(name.equals("com.android.internal.view.menu.IconMenuView")) {  
  44.                 try {  
  45.                     ClassLoader cl = getClassLoader();  
  46.                     Class<!----> clazz;  
  47.                     clazz = cl.loadClass("com.android.internal.view.menu.IconMenuView");  
  48.                     Constructor<!----> constructor = clazz.getConstructor(Context.class, AttributeSet.class);  
  49.                     Object view = constructor.newInstance(context, attrs);  
  50.                     ViewGroup vg = (ViewGroup) view;  
  51.                     // ここで色指定  
  52.                     // vg.setBackgroundColor(R.color.hoge); だとうまくいかなかった  
  53.                     //vg.setBackgroundColor(Color.CYAN); これはうまくいく  
  54.                     vg.setBackgroundColor(Color.parseColor("#66ffccff"));  
  55.                     //vg.setBackgroundResource(R.drawable.hoge); で画像を背景にすることも可能  
  56.                     return vg;  
  57.                 }  
  58.                 catch (ClassNotFoundException e) {  
  59.                     e.printStackTrace();  
  60.                 } catch (SecurityException e) {  
  61.                     e.printStackTrace();  
  62.                 } catch (NoSuchMethodException e) {  
  63.                     e.printStackTrace();  
  64.                 } catch (IllegalArgumentException e) {  
  65.                     e.printStackTrace();  
  66.                 } catch (InstantiationException e) {  
  67.                     e.printStackTrace();  
  68.                 } catch (IllegalAccessException e) {  
  69.                     e.printStackTrace();  
  70.                 } catch (InvocationTargetException e) {  
  71.                     e.printStackTrace();  
  72.                 }  
  73.             }  
  74.             return null;  
  75.          }  
  76.       };  
  77.       service.setFactory(factory);     
  78.     }  
  79. }  



Reflection を使っているので、通常の方法よりも
呼び出すときにオーバーヘッドが大きくなります。

#メニューボタンが押された一番最初しか呼ばれないし、
#実際そこまで気になるわけではないけど

メニューの中の各アイテムは com.android.internal.view.menu.IconMenuItemView
というクラスで TextView を extends してるので、同じようにして
文字色を変えられないかな、と思ったのですが変わりませんでした。残念。


あ、あと背景に指定する色を透過にしても、透過にはならないで白のパネルになりました。
白のパネルの上に載せる色を指定する、という感じなんですね。

0 件のコメント:

コメントを投稿