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

时间:2010-03-20 11:36:41

标签: android themes

我创建了一个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吗?如果有帮助,我的应用程序包含几个活动。

13 个答案:

答案 0 :(得分:80)

我也希望看到这个方法,你可以为你的所有活动设置一次。但据我所知,你必须在显示任何观点之前设置每个活动。

供参考检查:

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

答案 1 :(得分:55)

如果您想更改现有活动的主题,请在recreate()之后致电setTheme()

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

答案 2 :(得分:21)

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

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

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

编辑:

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

答案 3 :(得分:17)

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

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

答案 4 :(得分:9)

我们必须在调用 'super.onCreate()' 'setContentView()' 方法。

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

答案 5 :(得分:9)

我有类似的问题,我以这种方式解决了..

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

答案 6 :(得分:4)

而不是

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

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

答案 7 :(得分:2)

这是我为Material Design创建的。愿它对你有所帮助。

查看MultipleThemeMaterialDesign

答案 8 :(得分:2)

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

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)

这种方式对我有用:

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

答案 10 :(得分:1)

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

答案 11 :(得分:0)

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

答案 12 :(得分:0)

这对我没有影响:

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