Android 动态设置主题颜色

Android 动态设置主题颜色,android,android-activity,colors,themes,Android,Android Activity,Colors,Themes,我在android应用程序中(动态)使用主题,如下所示: my_layout.xml(摘录): } 我想知道的是,有没有办法在代码中做到这一点(更改主题颜色)?例如,我有以下代码(摘录): 它可以通过一些助手方法完成,该方法将对可用主题使用switch命令,并为主题返回正确的颜色。但我想知道是否有更好、更好、更快的方法 谢谢 如果我正确理解,你在寻找一种 从主题中提取一种风格 从所述样式中提取值(文本颜色) 让我们开始吧 // Extract ?my_item_style from a cont

我在android应用程序中(动态)使用主题,如下所示:

my_layout.xml(摘录):

}

我想知道的是,有没有办法在代码中做到这一点(更改主题颜色)?例如,我有以下代码(摘录):

它可以通过一些助手方法完成,该方法将对可用主题使用
switch
命令,并为主题返回正确的颜色。但我想知道是否有更好、更好、更快的方法


谢谢

如果我正确理解,你在寻找一种

  • 从主题中提取一种风格
  • 从所述样式中提取值(文本颜色)
  • 让我们开始吧

    // 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[]
    代价高昂,请将其设置为
    静态最终版
  • 如果要同时解析多个属性,则必须对属性数组进行排序!否则它有时会崩溃
    为您生成这样的数组和相应的索引

  • 如何通过
    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));
    
    你看过这个演示了吗

    设置活动:

    @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);
                }
            }
        };
    }
    

    请参阅演示的完整示例。

    我最终使用以下方法完成了演示:

    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());
        }
    }
    

    这将根据我的主题(我使用了前缀)返回颜色。

    鉴于每个资源都是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);
      }
    

    您从何处动态设置主题?你也能分享这些代码吗?@azizbekian我已经添加了MEUTILS类,尽管我认为这与我的问题无关。
    // assuming that MainTheme_Blue is default theme
    setTheme(getIntent().getIntExtra("theme", R.style.MainTheme_Blue));
    
    @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);
                }
            }
        };
    }
    
    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());
        }
    }
    
    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;
        }
    
    public static void onActivityCreateSetTheme(Activity activity)
      {
        int theme = getResourceId(R.style, activity.getClass().getSimpleName(), false);
        if(theme > 0) activity.setTheme(theme);
      }