背景

我正在我的“app manager”应用程序中开发主题选择器功能,并且我已成功为每个活动动态设置主题。

再次:这不是关于为活动设定主题。 这实际上适合我。

问题

这些活动正在显示正确的主题,但应用程序本身在启动应用程序时,无论我做什么,都会显示错误的主题。

这是一个问题,因为当用户打开应用程序时,他将看到应用程序主题的背景,并且仅在片刻之后,活动将显示用户选择的主题。

因此,如果应用程序具有白色背景,并且用户选择了具有黑色背景的主题,则订单将为:

应用程序显示白色背景 - >活动正在启动并显示黑色背景。

在截图中:

在此输入图像描述

所以这是错的。 在这种情况下,我需要它来显示黑色到黑色的背景。

仅当用户选择了基于Holo-light的主题(默认情况下应用程序具有此主题)时,它才能正常工作,因为颜色与打开应用程序时右侧显示的活动上的颜色相匹配。

我试过的

我有一个想法,设置应用程序的主题是空的一切,希望没有显示过渡,使用类似的东西:

<application
    ...
    android:theme="@android:style/Theme.Translucent.NoTitleBar" >

事实上,这里的一些人提出了类似的解决方案。

这有效,但它会导致糟糕的体验,因为在某些设备上显示第一个活动需要一些时间,因此,用户有很长时间没有看到任何内容,就像应用程序不是正在推出。

这个问题

我该如何解决这个问题?

我已经尝试在从Application扩展的类中设置主题,但它不会做任何事情,无论我在这个类中调用它。

===============>>#1 票数:9 已采纳

透明的应用程序主题与淡入动画

我最初的建议是使用透明全屏应用程序主题(没有操作栏)。

结合这一点,我总是建议从应用程序主题到活动主题的淡入淡出的alpha动画。 这可以防止在操作栏出现时对用户造成震动。

OP的代码将保持几乎相同,除了更改清单主题,并在一些基本活动类的onCreate()方法中添加alpha动画,如下例所示:


清单主题定义为:

android:theme="@android:style/Theme.Translucent.NoTitleBar"

基本活动onCreate()方法:

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

    // set your custom theme here before setting layout
    super.setTheme(android.R.style.Theme_Holo_Light_DarkActionBar);

    setContentView(R.layout.activity_main);

    overridePendingTransition(R.anim.fade_in, R.anim.fade_out);
}

基本淡入:

<?xml version="1.0" encoding="utf-8"?>
<alpha xmlns:android="http://schemas.android.com/apk/res/android"
    android:duration="2000"
    android:fromAlpha="0.0"
    android:toAlpha="1.0" />

基本淡出(不是真的需要,但为了完整性):

<?xml version="1.0" encoding="utf-8"?>
<alpha xmlns:android="http://schemas.android.com/apk/res/android"
    android:duration="2000"
    android:fromAlpha="1.0"
    android:toAlpha="0.0" />

当然,这里的动画持续时间比你投入生产的时间长 - 它们很长,所以你可以在开发阶段看到它们。


更新#1:

随后在@EmanuelMoecklin的评论中注意到,@ androiddeveloper认为这是考虑到的。 它也包含在dentex的回答中 但是,正如OP所述,特别是在旧设备上的弱点是用户在尝试启动应用程序时没有获得反馈。 该应用程序似乎需要很长时间才能启动。

在KitKat上,情况并非如此,因为状态栏和软键从透明变为黑色,而屏幕的其余部分仍然是透明的。

另一种方法是使用全屏黑色背景作为应用程序主题。 这就是Bitspin for Timely所做的,显然是基于该应用程序中令人惊叹的用户界面而被Google收购。 因此,在许多情况下,这种方法似乎是可以接受的。


更新#2:

为了加快对发布的看法,普通黑色主题的替代方案是使用带有应用程序徽标的全屏图像 - “闪屏”风格。 一旦启动,再次淡出活动。

透明主题使用透明的全屏图像是不可能的。 Android忽略图像的透明度(或将透明图像叠加到黑色背景上)。 OP在评论中指出了这一点。

我们既可以有没有图像的透明主题,也可以有带图像的不透明主题(也许是另一个问题的有趣主题)。


关于使用Manifest别名的说明

@ sergio91pt的另一个建议是在清单中为不同的活动使用别名。

虽然在某些情况下这可能是一种有用的技术,但在这种情况下它有一些缺点:

  1. 当主启动器别名发生更改时,即每次用户更改主题时,用户为活动创建的任何HOME屏幕快捷方式将停止工作。
  2. 某些设备/启动器激活和停用不同的别名非常慢。 根据我的经验,这可能需要几秒钟(Galaxy Nexus 4.1 iirc),在此期间您要么没有可见的启动图标,要么您有2个图标。
  3. 每个可能的主题都需要一个不同的别名 - 如果有许多不同的主题,这可能会很麻烦。

===============>>#2 票数:9

有点晚了,但这可能就是答案。 我偶然发现了它。

没有入场活动,没有自定义动画,没有黑客攻击。 只是主题中的一个属性。 Android深入挖掘其资源。

将以下属性添加到您的应用主题:

<!--
  ~ From Theme.NoDisplay, this disables the empty preview window probably
  ~ with an incorrect theme.
  -->
<item name="android:windowDisablePreview">true</item>

你完成了。 好好享受!

===============>>#3 票数:2

要在应用程序启动时修复任何闪烁(操作栏,标题...),我已设置清单

android:theme="@android:style/Theme.NoTitleBar"

对于我的两个主要活动(一个标签容器和一个设置活动,我从哪里切换主题,基于holo dark和light)

如果您使用某些“启动器活动”或“启动活动”,也会为他们应用Theme.NoTitleBar ,那么:

为每个活动声明了Theme.NoTitleBar ,在onCreate你必须:

  1. 使用setTitle(...)和THEN正确设置标题

  2. 使用setTheme(R.style.CustomAppTheme)setContentView(...)之前设置主题
    (你已经这样做了);

这将防止在切换主题(如果“即时”完成)和应用程序启动时闪烁操作栏/标题。

如果您想要自定义操作栏外观,这意味着默认的holo操作栏将不会在您的前面闪烁。

===============>>#4 票数:1

从清单上的活动主题(或未设置的应用程序)中检索过渡颜色。

目前,围绕此限制的唯一方法是为每个真实的Activity创建一个虚拟子类,例如。 MyActivityLight ,声明一个不同的主题。 活动别名不起作用,该属性将被忽略。

对于使用IntentFilter的活动,您应该只使用PackageManager#setComponentEnabledSetting()维护每个“type”中的一个。 请注意,更改可能需要几秒钟。

对于按类名启动的活动,您可以根据用户的主题推断出正确的前缀。


所以假设你有两个主题: AppTheme.DarkAppTheme.Light以及一些活动。 黑暗主题是默认主题。

原始清单:

<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.example">
    <application android:theme="@style/AppTheme.Dark">
        <activity 
                android:name=".PrivateActivity" 
                android:exported="false" />

        <activity android:name=".ShowActivity">
            <intent-filter>
                <action android:name="android.intent.action.VIEW" />
                <category android:name="android.intent.category.DEFAULT" />
                <data android:mimeType="text/plain" />
             </intent-filter>
        </activity>
    </application>
</manifest>

将上面的所有活动更改为抽象类,并创建以LightDark后缀的虚拟子类。

然后清单应该像这样改变:

<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.example">

    <!-- No application theme -->
    <application>
        <activity android:name=".PrivateActivityDark" 
            android:theme="@style/AppTheme.Dark"
            android:exported="false" />
        <activity android:name=".PrivateActivityLight" 
            android:theme="@style/AppTheme.Light"
            android:exported="false"
            android:enabled="false" />

        <activity 
            android:name=".ShowActivityDark"
            android:theme="@style/AppTheme.Dark">
            <intent-filter>
                <action android:name="android.intent.action.VIEW" />
                <category android:name="android.intent.category.DEFAULT" />
                <data android:mimeType="text/plain" />
             </intent-filter>
        </activity>
        <activity 
            android:name=".ShowActivityLight" 
            android:enabled="false"
            android:theme="@style/AppTheme.Light">
            <intent-filter>
                <action android:name="android.intent.action.VIEW" />
                <category android:name="android.intent.category.DEFAULT" />
                <data android:mimeType="text/plain" />
             </intent-filter>
        </activity>
    </application>
</manifest>

然后你可以得到这样的东西来获得主题的Activity类,给定一个抽象的Activity:

public static ComponentName getThemedActivityName(
        Context ctx, 
        Class<? extends Activity> clazz) {

    // Probably gets some value off SharedPreferences
    boolean darkTheme = isUsingDarkTheme(ctx);

    String baseName = clazz.getName();
    String name += (darkTheme) ? "Dark" : "Light";
    return new ComponentName(ctx, name);
}

public static void startThemedActivity(
        Activity ctx, 
        Class<? extends Activity> clazz) {
    Intent intent = new Intent();
    intent.setComponent(getThemedActivityName(ctx, clazz));
    ctx.startActivity(intent);
}

并且还会在主题更改时更改所需的启用状态。

public void onThemeChanged(Context ctx, boolean dark) {
    // save theme to SharedPreferences or similar and...

    final PackageManager pm = ctx.getPackageManager();
    final String pckgName = ctx.getPackageName();

    final PackageInfo pckgInfo;
    try {
        final int flags = PackageManager.GET_ACTIVITIES 
                             | PackageManager.GET_DISABLED_COMPONENTS;
        pckgInfo = pm.getPackageInfo(pckgName, flags);
    } catch (PackageManager.NameNotFoundException e) {
        throw new RuntimeException(e);
    }

    final ActivityInfo[] activities = pckgInfo.activities;

    for (ActivityInfo info: activities) {
        final boolean enable;
        if (info.theme == R.style.AppTheme_Light) {
            enable = !dark;
        } else if (info.theme == R.style.AppTheme_Dark) {
           enable = dark;
        } else {
           continue;
        }

        final int state = (enable) ? 
                PackageManager.COMPONENT_ENABLED_STATE_ENABLED :
                PackageManager.COMPONENT_ENABLED_STATE_DISABLED;

        final String name = info.targetActivity;
        final ComponentName cmp = new ComponentName(pckgName, name);
        pm.setComponentEnabledSetting(cmp, state, PackageManager.DONT_KILL_APP);
    }
}

如果在循环上执行IPC会让您感到害怕,只要多次调用onThemeChanged()按顺序运行,就可以在辅助线程上异步执行此操作。

请注意,在此示例中,我更改了所有活动(具有已知主题)的已启用状态,但只需对具有intent过滤器的活动执行此操作。 如果活动没有硬编码,那么这种方式就更容易了。

重要说明:正如Richard Le Mesurier和其他人所指出的,在Launcher Activities上使用此技术会删除或禁用主屏幕上的快捷方式(如果存在)。 这只是非启动器活动的解决方案。

  ask by android developer translate from so

未解决问题?本站智能推荐:

1回复

为Android应用程序提供多种主题颜色

我将创建一个称为“设置”的活动。 在此活动中,我想提供2个主题选项,分别是深色或浅色主题。 当用户选择任何主题颜色时,它将自动应用到主题颜色上。 通过我自己的搜索,大多数教程都将重点放在1个单一活动上。 目前,我在这些教程链接上http://www.developer.c
3回复

为Android应用程序设置Holo主题

我有一个简单的登录界面,包含用户名和密码。 我希望它以与您在冰淇淋三明治和蜂窝中的Holo主题中看到的相同的方式显示EditText字段。 在我的清单文件中 现在文本字段不应该看起来不同,例如没有顶部,左侧和右侧边框吗? 我似乎看起来完全一样。 我确信我做的事情基本上
1回复

无法在我的应用程序的代码中设置主题

我无法在Android应用程序中实现主题选择。 之前曾问过这个问题,但是解决方案-在setContentView之前调用application.setTheme(theme_id)-对我不起作用。 styles.xml中定义了2个主题: 这两个主题都可以在AndroidMan
1回复

在android中全局设置应用程序主题

我在相应的activity.java文件中分别为每个活动设置主题。 我可以在清单文件中全局设置主题,然后覆盖它以更改操作栏背景颜色等。 在AndroidManifest.xml中 在styles.xml中 但是它崩溃了,为什么呢?
2回复

创建从应用程序主题中设置的默认样式扩展的样式

我在应用程序主题中设置了默认按钮样式,以便它应用于应用程序中的每个按钮。 除了默认样式之外,还有一些按钮需要将其文本大写。 所以我想做的就是这样 (以下代码片段不起作用,因为我无法设置parent="?attr/materialButtonStyle" ): 是否可以扩展the
3回复

设置整个应用程序的文本颜色

我想为整个应用程序设置特定的文本颜色。 我已经定义了样式,但是不知道出了什么问题。 我定义了自己的样式: 对于TextAppearance 并在清单集中设置ActionBarTheme 任何帮助..
2回复

主题化的Android应用程序

我有一个android应用程序,需要为用户提供选择主题的选项。 现在我正在使用代码为对象添加颜色 我在很多这样的地方都使用过这类颜色。 有没有一种方法可以根据所选主题更改颜色值? 我检查了样式,但是我的问题是我的应用程序中可能有5种不同的文本颜色,但可能需要将其更改为全
1回复

Android应用程序主题覆盖视图主题

我已经开发Android应用程序已有一段时间了,几乎所有事情都应该如此。 但是,对于某些观点,我在主题方面遇到了一些问题。 我的应用程序使用基于AppCompat.Light的主题,如下所示: 一切看上去都很白净,但我有一个特定的屏幕有点暗。 因此,我为一些EditText字段创建
2回复

BottomSheetDialogFragment为Dark主题设置了错误的背景颜色

我最近在我的应用程序中添加了BottomSheetDialogFragment,但它将Material Dark主题的背景颜色显示为白色。 即使我使用 对于对话框的根布局,它仍然是白色的(但是在对话框之外这个attr是可以的)。 有没有人遇到过这个问题?
2回复

将背景图像设置为已经有主题的应用程序

嗨,我想将背景图像设置到已经具有主题的应用程序中。 现在我将代码更改为此 清单文件看起来像这样 现在设置了背景图像,但是我之前的主题(即Theme.NoTitleBar)无法正常工作。 理想的行为是背景图片和Theme.NoTitleBar应该都可以正常工作。 我