Androidアプリで、次のようにテーマを(動的に)使用しています:
my_layout.xml(抽出):
<TextView
Android:id="@+id/myItem"
style="?my_item_style" />
attrs.xml(抽出):
<attr name="my_item_style" format="reference" />
themes.xml(抽出):
<style name="MainTheme.Blue">
<item name="my_item_style">@style/my_item_style_blue</item>
</style>
<style name="MainTheme.Green">
<item name="my_item_style">@style/my_item_style_green<item>
</style>
styles.xml(抽出):
<style name="my_item_style_blue">
<item name="Android:textColor">@color/my_blue</item>
</style>
<style name="my_item_style_green">
<item name="Android:textColor">@color/my_blue</item>
</style>
ご覧のとおり、テーマを動的に設定しています。私はこのクラスを使用しています:
public class ThemeUtils {
private static int sTheme;
public final static int THEME_BLUE = 1;
public final static int THEME_GREEN = 2;
public static void changeToTheme(MainActivity activity, int theme) {
sTheme = theme;
activity.startActivity(new Intent(activity, MyActivity.class));
}
public static void onActivityCreateSetTheme(Activity activity)
{
switch (sTheme)
{
default:
case THEME_DEFAULT:
case THEME_BLUE:
activity.setTheme(R.style.MainTheme_Blue);
break;
case THEME_GREEN:
activity.setTheme(R.style.MainTheme_Green);
break;
}
}
}
知りたいのですが、コードでこれを行う方法(テーマの色を変更)はありますか?たとえば、次のコード(抽出)があります。
((TextView) findViewById(R.id.myItem)).setTextColor(R.color.blue);
これは、使用可能なテーマに対してswitch
コマンドを使用し、テーマに対して正しい色を返すヘルパーメソッドによって実行できます。しかし、私はいくつかのより良い、より良い、より速い方法があるかどうか知りたいのですが。
ありがとう!
私はついに次の方法を使用してそれを行いました:
public static int getColor(String colorName) {
Context ctx = getContext();
switch (sTheme) {
default:
case THEME_DEFAULT:
return ctx.getResources().getIdentifier("BLUE_" + colorName, "color", ctx.getPackageName());
case THEME_BLUE:
return ctx.getResources().getIdentifier("BLUE_" + colorName, "color", ctx.getPackageName());
case THEME_GREEN:
return ctx.getResources().getIdentifier("GREEN_" + colorName, "color", ctx.getPackageName());
}
}
これは私のテーマに応じて色を返します(私は接頭辞を使用しました)。
私が正確に理解しているなら、あなたはする方法を探しています
それに取り掛かろう。
// Extract ?my_item_style from a context/activity.
final TypedArray a = context.obtainStyledAttributes(new int[] { R.attr.my_item_style });
@StyleRes final int styleResId = a.getResourceId(0, 0);
a.recycle();
// Extract values from ?my_item_style.
final TypedArray b = context.obtainStyledAttributes(styleResId, new int[] { Android.R.attr.textColor });
final ColorStateList textColors = b.getColorStateList(0);
b.recycle();
// Apply extracted values.
if (textColors != null) {
textView.setTextColor(textColors);
}
いくつかの注意事項:
TypedArray
は、古いAPIレベルのカラー状態リストでサポートベクタードローアブルとテーマ参照の取得をサポートしていません。 AppCompat内部APIを使用する場合は、TintTypedArray
を試してください。int[]
を割り当てるとコストがかかるため、static final
にします。<declare-styleable>
は、このような配列と対応するインデックスを生成します。これを確認しました MultipleThemeMaterialDesign デモ?
SettingActivity:
@Override
protected void onCreate(Bundle savedInstanceState) {
Preferences.applyTheme(this);
getDelegate().installViewFactory();
getDelegate().onCreate(savedInstanceState);
super.onCreate(savedInstanceState);
setToolbar();
addPreferencesFromResource(R.xml.preferences);
Preferences.sync(getPreferenceManager());
mListener = new SharedPreferences.OnSharedPreferenceChangeListener() {
@Override
public void onSharedPreferenceChanged(SharedPreferences sharedPreferences, String key) {
Preferences.sync(getPreferenceManager(), key);
if (key.equals(getString(R.string.pref_theme))) {
finish();
final Intent intent = IntentCompat.makeMainActivity(new ComponentName(
SettingsActivity.this, MainActivity.class));
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | IntentCompat.FLAG_ACTIVITY_CLEAR_TASK);
startActivity(intent);
}
}
};
}
デモの完全な例を参照してください。
すべてのリソースがRクラスのフィールドであるという事実を考えると、リフレクションを使用してそれらを探すことができます。これはコストがかかりますが、int値を取得するため、取得後にそれらを格納してパフォーマンスの低下を回避できます。また、リソースを使用するメソッドは任意のintを使用するため、int変数をプレースホルダーとして使用し、目的の色をその中に入れることができます。
リソースを取得するため:
String awesomeColor = "blue";
int color = getResourceId(R.color, awesomeColor, false);
if(blue>0) ((TextView) findViewById(R.id.myItem)).setTextColor(color);
関数:
public static int getResourceId(Class rClass, String resourceText, boolean showExceptions){
String key = rClass.getName()+"-"+resourceText;
if(FailedResourceMap.containsKey(key)) return 0;
if(ResourceMap.containsKey(key)) return ResourceMap.get(rClass.getName()+"-"+resourceText);
try {
String originalText = resourceText;
if(Build.VERSION.SDK_INT>=Build.VERSION_CODES.Gingerbread){
resourceText = ValidationFunctions.normalizeText(resourceText);
}
resourceText = resourceText.replace("?", "").replace(" ", " ").replace(" ", "_").replace("(", "").replace(")", "");
int resource = rClass.getDeclaredField(resourceText).getInt(null);
ResourceMap.put(rClass.getName()+"-"+originalText, resource);
return resource;
} catch (IllegalAccessException | NullPointerException e) {
FailedResourceMap.put(key, 0);
if(showExceptions) e.printStackTrace();
} catch (NoSuchFieldException e) {
FailedResourceMap.put(key, 0);
if(showExceptions) e.printStackTrace();
}
return 0;
}
この処理は、すべてのAndroidリソースに有効です。中間変数を使用する代わりに、この方法でテーマを設定することもできます。
public static void onActivityCreateSetTheme(Activity activity)
{
int theme = getResourceId(R.style, activity.getClass().getSimpleName(), false);
if(theme > 0) activity.setTheme(theme);
}
Intent
を介してテーマIDを渡すのはどうですか?
Intent intent = new Intent(activity, MyActivity.class);
intent.putExtra("theme", R.style.MainTheme_Green);
activity.startActivity(intent);
そして、onCreate
:
// assuming that MainTheme_Blue is default theme
setTheme(getIntent().getIntExtra("theme", R.style.MainTheme_Blue));