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

我已经创建了一个 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吗? 我的应用程序由几个活动组成,如果有帮助的话。

214971 次浏览

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

参考资料如下:

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,你的活动将被重新创建,但是如果你在 super.onCreate(savedInstanceState);之前调用 setTheme,你的主题将被设置和活动 不再重现了

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




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

您可以完成的活动,并重新创建它以这种方式,您的活动将再次创建,所有的意见将创建与新的主题。

在调用 < em > ‘ super.onCreate ()’< em > ‘ setContentView ()’方法之前,我们必须设置主题。

查看这个 链接,它可以在运行时将新主题应用到整个应用程序。

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

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

如果您想改变一个已经存在的活动的主题,请在 setTheme()之后调用 recreate()

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

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

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

recreate()(正如 TPReal所提到的)只会重新启动当前活动,但是以前的活动仍然在后面的堆栈中,并且主题不会应用到它们。

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

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

编辑:

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

这是我为材料设计创作的,希望对你有所帮助。

看看 多主题材料设计

我知道我迟到了,但我想在这里贴出一个解决方案: 检查完整的源代码 给你。 这是我在使用首选项改变主题时使用的代码。

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

而不是

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

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

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

这对我毫无影响:

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

这条路对我有用:

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