Android Tutorial Changing the theme at runtime

Erel

Administrator
Staff member
Licensed User
Using the hooks feature it is possible to change the Activity theme at runtime.

The theme is set before the activity is actually shown. This means that in order to change the theme we need to destroy the activity and start it again. You can use StateManager to save the activity state.


The hook code is:
B4X:
#if java
public void _onCreate() {
   if (_theme_value != 0)
     setTheme(_theme_value);
}
#end if
There must be a process global int variable named Theme_Value. Note that the underscore is important. It prevents the obfuscator from changing the variable name which will cause the inline Java code to break.

Updates

Example updated and the selected theme value is stored in a file. The theme is set when the app starts.
 

Attachments

Last edited:

LucaMs

Expert
Licensed User
Just one question (out of laziness, I could search :D):
The range of values of _theme_value?

Ah, some themes can not be supported (material)... maybe a Try is sufficient, I think.
 

ArminKH

Well-Known Member
woooooooooow great
thank u erel
 

schimanski

Well-Known Member
Licensed User
Much thanks for this tutorial!

I have two questions:

1. Is it possible to change the color of the preference-screen at runtime. Now, the preference-screen get the design, which is based on the manifest-file.
2. Is it possible to check, which design is active?
 

trueboss323

Active Member
Licensed User
Hi Erel,
What correct code should I use when saving and loading the activity state?

And also, the Material themes do not work for me on Android 4.4
 
Last edited:

chrjak

Active Member
Licensed User
Hey Erel,

How can u access the Process_Global Main value from other modules?
_theme_value uses the current activity
and main_theme_value does not work :D

Normally it should be possible to start every other activity in the theme of the correct main theme value without restarting
 

chrjak

Active Member
Licensed User
Thank you :)

Is it everytime: modulename._theme_value?

eg. a Module named "Modul1"
modul1._theme_value
 

joneden

Active Member
Licensed User
Hi Erel,
This is great and I am working with it on my redesign to Material design. I have got two requests, one you should be able to easily tell me how to solve, the second maybe more tricky.

I save the theme ID into a variable that the statemanager then saves (StateManager.SetSetting("CurrentThemeId", Main.CurrentThemeId)). This works well for activities that are not the initial one. I need to get the data from the CurrentThemeId that is saved into the java _onCreate hook. What java would I need to add in order to get the data from the saved var BEFORE the page loads.

By using setTheme(2131165536); I have tested and this works so it's just the ID that I need.

The second issue that I have is re the main status bar changes properly to the colorPrimaryDark value in later activities but the main activity ALWAYS shows the value for the default theme. Any suggestions?

Regards

Jon

Further to the above I have managed to hack the first question by copying out java code from the source files - I'm sure there is a better way of doing it, second question still stands though.

B4X:
#if java
public static anywheresoftware.b4a.objects.collections.Map _settings = new anywheresoftware.b4a.objects.collections.Map();
public static String _settingsfilename = "settings.properties";

public static String  _getsetting2(anywheresoftware.b4a.BA _ba,String _key,String _defaultvalue) throws Exception{
    if (_settings.IsInitialized()==anywheresoftware.b4a.keywords.Common.False) {
        if (anywheresoftware.b4a.keywords.Common.File.Exists(_getfolder(_ba),_settingsfilename)) {
            _settings = anywheresoftware.b4a.keywords.Common.File.ReadMap(_getfolder(_ba),_settingsfilename);
         }else {
            if (true) return _defaultvalue;
         };
     };
    if (true) return BA.ObjectToString(_settings.GetDefault((Object)(_key.toLowerCase()),(Object)(_defaultvalue)));
    return "";
}

public static String  _getfolder(anywheresoftware.b4a.BA _ba) throws Exception{
    String _targetdir = "";
    _targetdir = anywheresoftware.b4a.keywords.Common.File.getDirInternal();
    if (anywheresoftware.b4a.keywords.Common.File.getExternalWritable()) {
        _targetdir = anywheresoftware.b4a.keywords.Common.File.getDirDefaultExternal();};
    if (true) return _targetdir;
    return "";
}

public void _onCreate() {
    _settings = new anywheresoftware.b4a.objects.collections.Map();
    BA activityBA;
    activityBA = new BA(this, layout, processBA, "amonet.mobile2", "amonet.mobile2.main");
    try{
        main._currentthemeid = (int)(Double.parseDouble(_getsetting2(activityBA,"CurrentThemeId","0")));
    } catch(Exception e){
        BA.LogInfo("Error" + e);
    }

    if (main._currentthemeid != 0)
        setTheme(main._currentthemeid);
   
}
#end if
 
Last edited:

joneden

Active Member
Licensed User
Hi Erel,
I can send you the full source - is there somewhere that I can send it directly to you?
Regards
Jon
 

joneden

Active Member
Licensed User
OK sample attached. I've just cut out as much as possible. Start the app and press login. Theme should switch to green and it does but the status bar stays blue.
With a second activity the status bar on that does show as green BUT always remains blue on the initial activity.

Essentially the status bar only ever is set on the main activity as the theme specified in the manifest file. Hopefully it's something obvious.
 

Attachments

Top