Set theme color dynamically

后端 未结 5 1428
北荒
北荒 2020-12-14 23:31

I am using themes (dynamically) in my android app, like this:

my_layout.xml (extract):



        
相关标签:
5条回答
  • 2020-12-14 23:57

    Have you check this MultipleThemeMaterialDesign demo?

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

    See full example for demo.

    0 讨论(0)
  • 2020-12-14 23:58

    Given the fact that every resource is a field into the R class, you can look for them using reflection. That's costly, but since you are going to get an int value, you can store them after you get them and avoid the performance drop. And since the methods that use resources take any int, you can use an int variable as placeholder, and then put the desired color into it.

    for getting any resource:

    String awesomeColor = "blue";
    int color = getResourceId(R.color, awesomeColor, false);
    if(blue>0) ((TextView) findViewById(R.id.myItem)).setTextColor(color);
    

    The function:

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

    Working version here: https://github.com/fcopardo/AndroidFunctions/blob/master/src/main/java/com/grizzly/functions/TextFunctions.java

    This treatment is valid for any android resource. You can set the theme this way too instead of using intermediate variables:

    public static void onActivityCreateSetTheme(Activity activity)
      {
        int theme = getResourceId(R.style, activity.getClass().getSimpleName(), false);
        if(theme > 0) activity.setTheme(theme);
      }
    
    0 讨论(0)
  • 2020-12-15 00:01

    If I understand corectly you're looking for a way to

    1. extract a style from a theme,
    2. extract a value (text color) from said style.

    Let's get to it.

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

    A couple of notes:

    1. TypedArray does not support getting support vector drawables and theme references in color state lists on older API levels. If you're willing to use AppCompat internal API you may want to try TintTypedArray.
    2. Allocating int[] all the time is costly, make it a static final.
    3. If you want to resolve multiple attributes at once the array of attributes has to be sorted! Else it crashes sometimes. <declare-styleable> generates such array and corresponding indices for you.
    0 讨论(0)
  • 2020-12-15 00:08

    I have finally done it using following method:

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

    This returns color according to my theme (I used prefixes).

    0 讨论(0)
  • 2020-12-15 00:09

    What about passing theme id via Intent?

    Intent intent = new Intent(activity, MyActivity.class);
    intent.putExtra("theme", R.style.MainTheme_Green);
    activity.startActivity(intent);
    

    And then in onCreate:

    // assuming that MainTheme_Blue is default theme
    setTheme(getIntent().getIntExtra("theme", R.style.MainTheme_Blue));
    
    0 讨论(0)
提交回复
热议问题