【问题标题】:Is it possible to set the style of a toolbar at runtime?是否可以在运行时设置工具栏的样式?
【发布时间】:2016-03-29 09:12:31
【问题描述】:

这是一个简短的问题:

我知道你可以通过 XML 创建一个带有指定主题的工具栏,例如 (link):

<android.support.v7.widget.Toolbar
    android:id="@+id/..."
    android:layout_width="match_parent"
    android:layout_height="?attr/actionBarSize"
    android:theme="@style/ThemeOverlay.AppCompat.Dark.ActionBar"
    app:popupTheme="@style/ThemeOverlay.AppCompat.Light"
    app:title="@string/..."/>

在我的例子中,在运行时,应用程序的某些内容可以是白色或深色。

是否可以在运行时将(支持库的)工具栏的主题设置为具有特定主题?

是否至少可以将里面的项目设置为具有正确的选择器和item-tint-color,以便按下它们仍然会有可见的效果(将背景颜色更改为白色,当它很暗时, 使效果不可见)?

【问题讨论】:

  • 是的,您可以在运行时更改工具栏的颜色 Toolbar toolbar = (Toolbar) (getActivity()).findViewById(R.id.toolbar); toolbar.setBackgroundColor(Color.parseColor("想要的颜色"));
  • @RakshitNawani 这个我已经做过了,但是标题、项目、溢出项目、选择器……都在一个主题中。我更改了背景和标题文本颜色,但项目看起来不太好。我想我应该使用 ViewStub,并在需要时决定要扩展哪个工具栏,但如果有更好的方法,我想知道它。
  • 我将很快发布一个答案,说明我为在不同的片段中显示工具栏的文本颜色、菜单选项和工具栏中的按钮所做的工作

标签: android android-support-library android-toolbar android-theme


【解决方案1】:

我发现,这是不可能的。

但是,我可以使用 ViewStub,并且当需要将工具栏设置为正确的样式时,我可以做到:

dark_toolbar.xml

<?xml version="1.0" encoding="utf-8"?>
<android.support.v7.widget.Toolbar
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="?attr/actionBarSize"
    app:popupTheme="@style/ThemeOverlay.AppCompat.Light"
    app:theme="@style/ThemeOverlay.AppCompat.Dark.ActionBar"/>

light_toolbar.xml

<?xml version="1.0" encoding="utf-8"?>
<android.support.v7.widget.Toolbar
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="?attr/actionBarSize"
    app:popupTheme="@style/ThemeOverlay.AppCompat.Light"
    app:theme="@style/ThemeOverlay.AppCompat.ActionBar"/>

布局:

            <ViewStub
                android:id="@+id/..."
                android:layout_width="match_parent"
                android:layout_height="?attr/actionBarSize"/>

代码:

    ViewStub viewStub = ...
    viewStub.setLayoutResource(...);
    final Toolbar toolbar = (Toolbar) viewStub.inflate();

如果我需要“更改工具栏的主题”,在它已经显示后,我可以使用 2 个工具栏的 viewSwitcher(每个工具栏都有不同的主题),并且对于一个上的每个函数调用,为其他也是。而当我需要在主题之间切换时,我可以在 viewSwitcher 中的视图之间进行切换。

与切换主题不同,但仍然是一个不错的解决方法。

【讨论】:

  • 但是这个主题是如何变化的?您正在工具栏布局而不是主题属性之间切换。
  • 我知道。正如我所写,这是不可能的,所以至少我必须拥有正确的初始化状态。另一种选择是拥有 2 个工具栏的 viewSwitcher(每个主题一个),并且对于您在其中一个上调用的每个功能,也可以在另一个上调用它(例如,添加菜单项)。当您想切换主题时,您可以在工具栏之间切换。
  • 但这不是主题的动态变化,你所做的是一个很好的解决方法,可能会导致大量 LOC,如果你的应用程序设计只有两个主题,那没关系,但是如果你有10个?但是,正如您所说,它是一种按预期工作的解决方法。
  • 我知道。动态主题在任何类型视图的同一实例上都不太可能。至于 10 个主题的例子,我的解决方案可以进一步扩展。你可以有一个扩展 ViewAnimator 的类,它为你想要的每个主题保存一个工具栏,并且在这个类中,每个 Toolbar 函数都有一个函数,它将为它拥有的每个工具栏调用它。它创建了很多工具栏(本例中为 10 个),但它会起作用。不是完美的解决方案,但它可以工作。
  • Hmmmm...嗯,这是真的,但现在支持 Java 8,您可以使用 Lambda(虽然我自己从未做过)查看每个工具栏,并调用您需要的函数在上面。因此,“toolbar.setTitle”的每一行(例如)仍然是一行代码,因为您调用 lambda 行来遍历每个工具栏。
【解决方案2】:

Toolbar 类中有一个方法叫做
setPopupTheme();

指定膨胀弹出菜单时使用的主题。默认情况下,使用与工具栏本身相同的主题。

只需更改工具栏背景/弹出主题,您就可以创建一个扩展 Toolbar 的自定义 class,您可以向其发布事件,以便它可以在当前 Stack 拥有的所有 Activity/Fragments 中动态更改其 background/popup theme

例如,我假设您对如何使用 EventBus 有一个想法,请考虑以下课程:

    public class ThemeableToolbar extends Toolbar {


    private boolean isSemiTransparent;

    public ThemeableToolbar(Context context) {
        super(context);
        init();
    }

    public ThemeableToolbar(Context context, AttributeSet attrs) {
        super(context, attrs);
        init();
    }

    public ThemeableToolbar(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        init();
    }

    private void init() {
        if (isInEditMode()) return;
        int primary = PrefHelper.getInt(PrefConstant.PRIMARY_COLOR);
        if (primary == 0) {
            primary = ActivityCompat.getColor(getContext(), R.color.primary);
        }
        if (isSemiTransparent()) {
            AnimUtil.animateColorChange(this, ColorUtils.setAlphaComponent(primary, 40), null);
        } else {
            AnimUtil.animateColorChange(this, primary, null);
        }
    }

    @Override protected void onAttachedToWindow() {
        super.onAttachedToWindow();
        if (isInEditMode()) return;
        if (!EventBus.getDefault().isRegistered(this)) {
            EventBus.getDefault().register(this);
        }
    }

    @Override protected void onDetachedFromWindow() {
        if (isInEditMode()) return;
        if (EventBus.getDefault().isRegistered(this)) {
            EventBus.getDefault().unregister(this);
        }
        super.onDetachedFromWindow();
    }

    public void onEvent(ThemeModel themeModel) {
        init();
    }

    public boolean isSemiTransparent() {
        return isSemiTransparent;
    }

    public void setIsSemiTransparent(boolean isSemiTransparent) {
        this.isSemiTransparent = isSemiTransparent;
        setBackgroundColor(ColorUtils.setAlphaComponent(ViewHelper.getPrimaryColor(getContext()), 40));
    }
}

ThemeModel 只是一个普通的 java 类,它被传递给 EventBus onEvent 以通知它。

编辑以便能够更改整个 Activity Theme 我建议你有一个 BaseActivity 来注册要传递给它的事件,当收到事件时你应该然后通过调用recreate(); 重新创建您的活动,这将导致重新创建扩展BaseActivity 的活动。在您的BaseActivity 中调用super.onCreate(....) 之前,请确保您设置了所需的主题。也许在 android Preferences 中存储一个引用,这样你就可以知道要设置哪个主题?

【讨论】:

  • 我不认为这会改变项目的显示方式及其选择器,因此它不是全主题更改支持。我的意思类似于我在 XML 上设置的主题。无论如何,我认为就像其他主题设置一样,这需要一个 ViewStub 或其他东西。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2019-08-24
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2010-12-13
  • 1970-01-01
  • 2021-06-30
相关资源
最近更新 更多