如何在 Android 运行时更改当前主题

发布于 2024-08-26 09:49:50 字数 688 浏览 7 评论 0 原文

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

当用户选择主题时,将执行以下代码:

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

但是,即使我已经使用调试器检查了代码是否正在执行,我在用户界面中看不到任何变化。

主题在 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>

知道可能发生什么以及如何解决它吗? 我应该在代码中的任何特殊点调用 setTheme 吗?如果有帮助的话,我的应用程序由多个活动组成。

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

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.

<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.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(13

木格 2024-09-02 09:49:50

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

作为参考,请检查以下内容:

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

编辑(从该论坛复制):

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

编辑
如果您在 super.onCreate(savedInstanceState); 之后调用 setTheme,您的 Activity 会重新创建,但如果您在 super.onCreate(savedInstanceState) 之前调用 setTheme ); 您的主题和活动将设置
不再重新创建

  protected void onCreate(Bundle savedInstanceState) {
     setTheme(android.R.style.Theme_Dark);
     super.onCreate(savedInstanceState);


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

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

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

Edit
If you call setTheme after super.onCreate(savedInstanceState); your activity recreated but if you call setTheme before super.onCreate(savedInstanceState); your theme will set and activity
does not recreate anymore

  protected void onCreate(Bundle savedInstanceState) {
     setTheme(android.R.style.Theme_Dark);
     super.onCreate(savedInstanceState);


    // ...
    setContentView(R.layout.main);
}
北城孤痞 2024-09-02 09:49:50

如果您想更改现有活动的主题,请调用 < 之后 >recreate()代码>setTheme()。

注意:如果在onCreate()中更改主题,请勿调用recreate,以避免无限循环。

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

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

谜兔 2024-09-02 09:49:50

recreate() (如TPReal所述)只会重新启动当前活动,但以前的活动仍将在后台堆栈中,主题将不会应用于它们。

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

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

编辑:

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

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.

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.

烟燃烟灭 2024-09-02 09:49:50

我遇到了同样的问题,但我找到了解决方案。

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

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);
    }
}
泪眸﹌ 2024-09-02 09:49:50

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

查看此链接< /a> 用于在运行时将新主题应用于整个应用程序。

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

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

就是爱搞怪 2024-09-02 09:49:50

我有一个类似的问题,我用这种方式解决了。

@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

}

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

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

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

Bundle temp_bundle = new Bundle();
onSaveInstanceState(temp_bundle);
Intent intent = new Intent(this, MainActivity.class);
intent.putExtra("bundle", temp_bundle);
startActivity(intent);
finish();
滥情稳全场 2024-09-02 09:49:50

而不是

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

使用

setTheme(R.style.BlackTheme);

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

super.onCreate(savedInstanceState);

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

setContentView(R.layout.activity_some_layout);

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

YourActivity.this.recreate();

您必须重新创建活动,否则 - 更改不会发生

Instead of

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

use

setTheme(R.style.BlackTheme);

My code: in onCreate() method:

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

∝单色的世界 2024-09-02 09:49:50

这是我为材料设计创建的。愿它会对你有所帮助。

看看 MultipleThemeMaterialDesign

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

Have a look for MultipleThemeMaterialDesign

儭儭莪哋寶赑 2024-09-02 09:49:50

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

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

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..

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);
}
单身情人 2024-09-02 09:49:50

这种方式对我有用:

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

    setContentView(R.layout.activity_main);
}

然后你想更改一个新主题:

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

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();
在梵高的星空下 2024-09-02 09:49:50

您可以完成活动并随后重新创建它,这样您的活动将再次创建,并且所有视图都将使用新主题创建。

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.

一个人的夜不怕黑 2024-09-02 09:49:50

在 setTheme() 之后调用 SetContentView(Resource.Layout.Main)。

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

尬尬 2024-09-02 09:49:50

这对我没有影响:

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

但这有效:

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

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();
}
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文