如何在运行时在Android中改变当前主题[复制]

时间:2021-01-04 23:00:16

This question already has an answer here:

这个问题已经有了答案:

I've created a PreferenceActivity that allows the user to choose the theme he wants to apply to the entire application.

我创建了一个PreferenceActivity,允许用户选择他想要应用到整个应用程序的主题。

When the user selects a theme, this code is executed:

当用户选择主题时,执行此代码:

if (...) {
    getApplication().setTheme(R.style.BlackTheme);
} else {
    getApplication().setTheme(R.style.LightTheme);
}

But, even though I've checked with the debugger that the code is being executed, I can't see any change in the user interface.

但是,尽管我已经与调试器检查了正在执行的代码,但是我在用户界面中看不到任何更改。

Themes are defined in res/values/styles.xml, and Eclipse does not show any error.

主题在res/values/styles中定义。xml和Eclipse没有显示任何错误。

<resources>
    <style name="LightTheme" parent="@android:style/Theme.Light">
    </style>

    <style name="BlackTheme" parent="@android:style/Theme.Black">
    </style>    
</resources>

Any idea about what could be happening and how to fix it? Should I call setTheme at any special point in the code? My application consists of several Activities if that helps.

你知道会发生什么以及如何解决吗?我应该在代码中的任何特殊点调用setTheme吗?如果有帮助的话,我的应用程序包含几个活动。

13 个解决方案

#1


70  

I would like to see the method too, where you set once for all your activities. But as far I know you have to set in each activity before showing any views.

我也想看看这个方法,您为所有的活动设置一次。但据我所知,在显示任何视图之前,您必须先设置每个活动。

For reference check this:

检查供参考:

http://www.anddev.org/applying_a_theme_to_your_application-t817.html

http://www.anddev.org/applying_a_theme_to_your_application-t817.html

Edit (copied from that forum):

编辑(从该论坛拷贝):

protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);

    // Call setTheme before creation of any(!) View.
     setTheme(android.R.style.Theme_Dark);

    // ...
    setContentView(R.layout.main);
}

#2


43  

If you want to change theme of an already existing activity, call recreate() after setTheme().

如果您想更改已存在活动的主题,请在setTheme()之后调用restart()。

Note: don't call recreate if you change theme in onCreate(), to avoid infinite loop.

注意:如果在onCreate()中更改了主题,不要调用re,以避免无限循环。

#3


17  

recreate() (as mentioned by TPReal) will only restart current activity, but the previous activities will still be in back stack and theme will not be applied to them.

重新创建()(正如TPReal所提到的)只会重新启动当前的活动,但是之前的活动仍然会在堆栈中,主题将不会应用于它们。

So, another solution for this problem is to recreate the task stack completely, like this:

因此,这个问题的另一个解决方案是完全重新创建任务堆栈,如下所示:

    TaskStackBuilder.create(getActivity())
            .addNextIntent(new Intent(getActivity(), MainActivity.class))
            .addNextIntent(getActivity().getIntent())
            .startActivities();

EDIT:

编辑:

Just put the code above after you perform changing of theme on the UI or somewhere else. All your activities should have method setTheme() called before onCreate(), probably in some parent activity. It is also a normal approach to store the theme chosen in SharedPreferences, read it and then set using setTheme() method.

在UI或其他地方执行主题更改之后,只需将代码放在上面。您的所有活动应该在onCreate()之前调用方法setTheme(),可能在某些父活动中。它也是一个普通的方法来存储在SharedPreferences中选择的主题,读取它,然后使用setTheme()方法进行设置。

#4


15  

i got the same problem but i found the solution.

我遇到了同样的问题,但我找到了解决办法。

public class EditTextSmartPhoneActivity extends Activity implements DialogInterface.OnClickListener
{
    public final static int CREATE_DIALOG  = -1;
    public final static int THEME_HOLO_LIGHT  = 0;
    public final static int THEME_BLACK  = 1;

    int position;

    /** Called when the activity is first created. */
    @Override
    public void onCreate(Bundle savedInstanceState) 
    {
        position = getIntent().getIntExtra("position", -1);

        switch(position)
        {
        case CREATE_DIALOG:
            createDialog();
            break;
        case THEME_HOLO_LIGHT:
            setTheme(android.R.style.Theme_Holo_Light);
            break;
        case THEME_BLACK:
            setTheme(android.R.style.Theme_Black);
            break;
        default:
        }

        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);

    }

    private void createDialog()
    {
        /** Options for user to select*/
        String choose[] = {"Theme_Holo_Light","Theme_Black"};

        AlertDialog.Builder b = new AlertDialog.Builder(this);

        /** Setting a title for the window */
        b.setTitle("Choose your Application Theme");

        /** Setting items to the alert dialog */
        b.setSingleChoiceItems(choose, 0, null);

        /** Setting a positive button and its listener */
        b.setPositiveButton("OK",this);

        /** Setting a positive button and its listener */
        b.setNegativeButton("Cancel", null);

        /** Creating the alert dialog window using the builder class */
        AlertDialog d = b.create();

        /** show dialog*/
        d.show();
    }

    @Override
    public void onClick(DialogInterface dialog, int which) {
        // TODO Auto-generated method stub
        AlertDialog alert = (AlertDialog)dialog;
        int position = alert.getListView().getCheckedItemPosition();

        finish();
        Intent intent = new Intent(this, EditTextSmartPhoneActivity.class);
        intent.putExtra("position", position);
        intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP); 
        intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
        startActivity(intent);
    }
}

#5


9  

We have to set theme before calling 'super.onCreate()' and 'setContentView()' method.

我们必须在调用“super.onCreate()”和“setContentView()”方法之前设置主题。

Check out this link for applying new theme to whole application at runtime.

请查看此链接,以便在运行时将新主题应用到整个应用程序。

#6


8  

I had a similar problem and I solved in this way..

我遇到过类似的问题,我用这种方法解决了。

@Override
public void onCreate(Bundle savedInstanceState) {

    if (getIntent().hasExtra("bundle") && savedInstanceState==null){
        savedInstanceState = getIntent().getExtras().getBundle("bundle");
    }

    //add code for theme

    switch(theme)
    {
    case LIGHT:
        setTheme(R.style.LightTheme);
        break;
    case BLACK:
        setTheme(R.style.BlackTheme);
        break;

    default:
    }
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);
    //code

}

this code is for recreate the Activity saving Bundle and changing the theme. You have to write your own onSaveInstanceState(Bundle outState); From API-11 you can use the method recreate() instead

此代码用于重新创建活动保存包并更改主题。必须编写自己的onSaveInstanceState(Bundle outState);从API-11中,您可以使用方法rebuild ()

Bundle temp_bundle = new Bundle();
onSaveInstanceState(temp_bundle);
Intent intent = new Intent(this, MainActivity.class);
intent.putExtra("bundle", temp_bundle);
startActivity(intent);
finish();

#7


2  

This is what i have created for Material Design. May it will helpful you.

这是我为材料设计创造的。但愿这对你有帮助。

Have a look for MultipleThemeMaterialDesign

你是否想要一款多功能的设计?

#8


2  

I know that i am late but i would like to post a solution here: Check the full source code here. This is the code i used when changing theme using preferences..

我知道我迟到了,但我想在这里发布一个解决方案:在这里检查完整的源代码。这是我在使用preferences更改主题时使用的代码。

SharedPreferences pref = PreferenceManager
        .getDefaultSharedPreferences(this);
String themeName = pref.getString("prefSyncFrequency3", "Theme1");
if (themeName.equals("Africa")) {
    setTheme(R.style.AppTheme);
} else if (themeName.equals("Colorful Beach")) {
    //Toast.makeText(this, "set theme", Toast.LENGTH_SHORT).show();
    setTheme(R.style.beach);
} else if (themeName.equals("Abstract")) {
    //Toast.makeText(this, "set theme", Toast.LENGTH_SHORT).show();
    setTheme(R.style.abstract2);
} else if (themeName.equals("Default")) {
    setTheme(R.style.defaulttheme);
}

#9


2  

Instead of

而不是

getApplication().setTheme(R.style.BlackTheme);

use

使用

setTheme(R.style.BlackTheme);

My code: in onCreate() method:

我的代码:在onCreate()方法中:

super.onCreate(savedInstanceState);

if(someExpression) {
    setTheme(R.style.OneTheme);
} else {
    setTheme(R.style.AnotherTheme);
}

setContentView(R.layout.activity_some_layout);

Somewhere (for example, on a button click):

某处(例如,单击按钮):

YourActivity.this.recreate();

You have to recreate activity, otherwise - change won't happen

你必须重新创造活动,否则不会发生改变。

#10


2  

This way work for me:

这种方式对我有效:

  @Override
protected void onCreate(Bundle savedInstanceState) {
    setTheme(GApplication.getInstance().getTheme());
    super.onCreate(savedInstanceState);

    setContentView(R.layout.activity_main);
}

Then you want to change a new theme:

然后你想改变一个新的主题:

GApplication.getInstance().setTheme(R.style.LightTheme);
recreate();

#11


1  

You can finish the Acivity and recreate it afterwards in this way your activity will be created again and all the views will be created with the new theme.

您可以完成Acivity,然后以这种方式重新创建您的活动,并且所有的视图都将使用新的主题创建。

#12


0  

Call SetContentView(Resource.Layout.Main) after setTheme().

调用SetContentView(Resource.Layout.Main)setTheme()。

#13


0  

This had no effect for me:

这对我没有影响:

public void changeTheme(int newTheme) {
    setTheme(newTheme);
    recreate();
}

But this worked:

但这工作:

int theme = R.style.default;

protected void onCreate(Bundle savedInstanceState) {
    setTheme(this.theme);
    super.onCreate(savedInstanceState);
}

public void changeTheme(int newTheme) {
    this.theme = newTheme;
    recreate();
}

#1


70  

I would like to see the method too, where you set once for all your activities. But as far I know you have to set in each activity before showing any views.

我也想看看这个方法,您为所有的活动设置一次。但据我所知,在显示任何视图之前,您必须先设置每个活动。

For reference check this:

检查供参考:

http://www.anddev.org/applying_a_theme_to_your_application-t817.html

http://www.anddev.org/applying_a_theme_to_your_application-t817.html

Edit (copied from that forum):

编辑(从该论坛拷贝):

protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);

    // Call setTheme before creation of any(!) View.
     setTheme(android.R.style.Theme_Dark);

    // ...
    setContentView(R.layout.main);
}

#2


43  

If you want to change theme of an already existing activity, call recreate() after setTheme().

如果您想更改已存在活动的主题,请在setTheme()之后调用restart()。

Note: don't call recreate if you change theme in onCreate(), to avoid infinite loop.

注意:如果在onCreate()中更改了主题,不要调用re,以避免无限循环。

#3


17  

recreate() (as mentioned by TPReal) will only restart current activity, but the previous activities will still be in back stack and theme will not be applied to them.

重新创建()(正如TPReal所提到的)只会重新启动当前的活动,但是之前的活动仍然会在堆栈中,主题将不会应用于它们。

So, another solution for this problem is to recreate the task stack completely, like this:

因此,这个问题的另一个解决方案是完全重新创建任务堆栈,如下所示:

    TaskStackBuilder.create(getActivity())
            .addNextIntent(new Intent(getActivity(), MainActivity.class))
            .addNextIntent(getActivity().getIntent())
            .startActivities();

EDIT:

编辑:

Just put the code above after you perform changing of theme on the UI or somewhere else. All your activities should have method setTheme() called before onCreate(), probably in some parent activity. It is also a normal approach to store the theme chosen in SharedPreferences, read it and then set using setTheme() method.

在UI或其他地方执行主题更改之后,只需将代码放在上面。您的所有活动应该在onCreate()之前调用方法setTheme(),可能在某些父活动中。它也是一个普通的方法来存储在SharedPreferences中选择的主题,读取它,然后使用setTheme()方法进行设置。

#4


15  

i got the same problem but i found the solution.

我遇到了同样的问题,但我找到了解决办法。

public class EditTextSmartPhoneActivity extends Activity implements DialogInterface.OnClickListener
{
    public final static int CREATE_DIALOG  = -1;
    public final static int THEME_HOLO_LIGHT  = 0;
    public final static int THEME_BLACK  = 1;

    int position;

    /** Called when the activity is first created. */
    @Override
    public void onCreate(Bundle savedInstanceState) 
    {
        position = getIntent().getIntExtra("position", -1);

        switch(position)
        {
        case CREATE_DIALOG:
            createDialog();
            break;
        case THEME_HOLO_LIGHT:
            setTheme(android.R.style.Theme_Holo_Light);
            break;
        case THEME_BLACK:
            setTheme(android.R.style.Theme_Black);
            break;
        default:
        }

        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);

    }

    private void createDialog()
    {
        /** Options for user to select*/
        String choose[] = {"Theme_Holo_Light","Theme_Black"};

        AlertDialog.Builder b = new AlertDialog.Builder(this);

        /** Setting a title for the window */
        b.setTitle("Choose your Application Theme");

        /** Setting items to the alert dialog */
        b.setSingleChoiceItems(choose, 0, null);

        /** Setting a positive button and its listener */
        b.setPositiveButton("OK",this);

        /** Setting a positive button and its listener */
        b.setNegativeButton("Cancel", null);

        /** Creating the alert dialog window using the builder class */
        AlertDialog d = b.create();

        /** show dialog*/
        d.show();
    }

    @Override
    public void onClick(DialogInterface dialog, int which) {
        // TODO Auto-generated method stub
        AlertDialog alert = (AlertDialog)dialog;
        int position = alert.getListView().getCheckedItemPosition();

        finish();
        Intent intent = new Intent(this, EditTextSmartPhoneActivity.class);
        intent.putExtra("position", position);
        intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP); 
        intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
        startActivity(intent);
    }
}

#5


9  

We have to set theme before calling 'super.onCreate()' and 'setContentView()' method.

我们必须在调用“super.onCreate()”和“setContentView()”方法之前设置主题。

Check out this link for applying new theme to whole application at runtime.

请查看此链接,以便在运行时将新主题应用到整个应用程序。

#6


8  

I had a similar problem and I solved in this way..

我遇到过类似的问题,我用这种方法解决了。

@Override
public void onCreate(Bundle savedInstanceState) {

    if (getIntent().hasExtra("bundle") && savedInstanceState==null){
        savedInstanceState = getIntent().getExtras().getBundle("bundle");
    }

    //add code for theme

    switch(theme)
    {
    case LIGHT:
        setTheme(R.style.LightTheme);
        break;
    case BLACK:
        setTheme(R.style.BlackTheme);
        break;

    default:
    }
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);
    //code

}

this code is for recreate the Activity saving Bundle and changing the theme. You have to write your own onSaveInstanceState(Bundle outState); From API-11 you can use the method recreate() instead

此代码用于重新创建活动保存包并更改主题。必须编写自己的onSaveInstanceState(Bundle outState);从API-11中,您可以使用方法rebuild ()

Bundle temp_bundle = new Bundle();
onSaveInstanceState(temp_bundle);
Intent intent = new Intent(this, MainActivity.class);
intent.putExtra("bundle", temp_bundle);
startActivity(intent);
finish();

#7


2  

This is what i have created for Material Design. May it will helpful you.

这是我为材料设计创造的。但愿这对你有帮助。

Have a look for MultipleThemeMaterialDesign

你是否想要一款多功能的设计?

#8


2  

I know that i am late but i would like to post a solution here: Check the full source code here. This is the code i used when changing theme using preferences..

我知道我迟到了,但我想在这里发布一个解决方案:在这里检查完整的源代码。这是我在使用preferences更改主题时使用的代码。

SharedPreferences pref = PreferenceManager
        .getDefaultSharedPreferences(this);
String themeName = pref.getString("prefSyncFrequency3", "Theme1");
if (themeName.equals("Africa")) {
    setTheme(R.style.AppTheme);
} else if (themeName.equals("Colorful Beach")) {
    //Toast.makeText(this, "set theme", Toast.LENGTH_SHORT).show();
    setTheme(R.style.beach);
} else if (themeName.equals("Abstract")) {
    //Toast.makeText(this, "set theme", Toast.LENGTH_SHORT).show();
    setTheme(R.style.abstract2);
} else if (themeName.equals("Default")) {
    setTheme(R.style.defaulttheme);
}

#9


2  

Instead of

而不是

getApplication().setTheme(R.style.BlackTheme);

use

使用

setTheme(R.style.BlackTheme);

My code: in onCreate() method:

我的代码:在onCreate()方法中:

super.onCreate(savedInstanceState);

if(someExpression) {
    setTheme(R.style.OneTheme);
} else {
    setTheme(R.style.AnotherTheme);
}

setContentView(R.layout.activity_some_layout);

Somewhere (for example, on a button click):

某处(例如,单击按钮):

YourActivity.this.recreate();

You have to recreate activity, otherwise - change won't happen

你必须重新创造活动,否则不会发生改变。

#10


2  

This way work for me:

这种方式对我有效:

  @Override
protected void onCreate(Bundle savedInstanceState) {
    setTheme(GApplication.getInstance().getTheme());
    super.onCreate(savedInstanceState);

    setContentView(R.layout.activity_main);
}

Then you want to change a new theme:

然后你想改变一个新的主题:

GApplication.getInstance().setTheme(R.style.LightTheme);
recreate();

#11


1  

You can finish the Acivity and recreate it afterwards in this way your activity will be created again and all the views will be created with the new theme.

您可以完成Acivity,然后以这种方式重新创建您的活动,并且所有的视图都将使用新的主题创建。

#12


0  

Call SetContentView(Resource.Layout.Main) after setTheme().

调用SetContentView(Resource.Layout.Main)setTheme()。

#13


0  

This had no effect for me:

这对我没有影响:

public void changeTheme(int newTheme) {
    setTheme(newTheme);
    recreate();
}

But this worked:

但这工作:

int theme = R.style.default;

protected void onCreate(Bundle savedInstanceState) {
    setTheme(this.theme);
    super.onCreate(savedInstanceState);
}

public void changeTheme(int newTheme) {
    this.theme = newTheme;
    recreate();
}