【问题标题】:How to show the shadow of the ActionBar&Toolbar of the support library on all Android versions?如何在所有Android版本上显示支持库的ActionBar&Toolbar的影子?
【发布时间】:2015-02-13 00:01:54
【问题描述】:

这是一个简单的问题:

我使用新的支持库,它允许我拥有一个 Toolbar 实例,甚至将其设置为活动的 actionBar(或使用默认的)。

如何自定义 Toolbar(或默认 ActionBar)投射的阴影?

我尝试使用“setElevation”(在他们两个上),但它似乎在 Android Lollipop 上没有任何作用。

另外,我找不到如何自定义棒棒糖前版本的阴影。可能有一个API吗?或者至少是一个drawable(我没有找到,即使我试过了)?


好的,我已经设法找到了接下来的事情:

对于 Lollipop 和 pre-Lollipop,当您的活动使用正常的 AppCompat 主题(例如“Theme.AppCompat.Light”)时,阴影应该看起来不错。

但是,当您使用“setSupportActionBar”(并使用适当的主题,例如“Theme.AppCompat.Light.NoActionBar”)时,阴影会出现一些问题。

对于棒棒糖之前的版本,您可以在工具栏下方放置一个 FrameLayout,它看起来与用于普通主题的完全一样,例如:

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical" >

    <android.support.v7.widget.Toolbar
        android:id="@+id/toolbar"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:minHeight="?attr/actionBarSize"
        app:theme="@style/ThemeOverlay.AppCompat.ActionBar" />

    <FrameLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_below="@+id/toolbar"
        android:foreground="?android:windowContentOverlay"
        android:visibility="@integer/action_bar_shadow_background_visibility" />

    <TextView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_below="@+id/toolbar"
        android:text="@string/hello_world" />

</RelativeLayout>

您可以使用 FrameLayout 作为活动的内容,或者使用我所做的。您还可以通过将整数 0 设置为 pre-lollipop 并将 2 设置为 Lollipop 及更高版本来设置其可见性,就像我对“action_bar_shadow_background_visibility”所做的那样。

这是一个丑陋的解决方案,但它有效,但仅适用于棒棒糖之前的版本。

无论如何,如果我使用“setSupportActionBar”,我仍然找不到为 Lollipop 很好地显示阴影的方法。我尝试在工具栏和操作栏上使用“setElevation”(在调用“setSupportActionBar”之后使用“getSupportActionBar”)。

我也不知道如何获得 actionbar 的标准高度,因为我注意到很多教程都说要使用“minHeight”作为工具栏。对此也很感激。

谁能帮我解决这个问题?

再次澄清,这就是我的要求:

  • 对于 Pre-Lollipop,显示在工具栏和操作栏的支持库中使用的相同阴影。
  • Lo​​llipop 也一样(但使用 Lollipop 的那个)
  • 额外:在 Lollipop 上将阴影自定义为更“精致”(并且可能在所有版本上进行自定义)。
  • 补充:为什么工具栏的 minHeight 得到的是操作栏高度的值,而不是高度本身?

编辑:好的,到目前为止,这是我模仿棒棒糖阴影所做的工作:

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical" >

    <android.support.v7.widget.Toolbar
        android:id="@+id/toolbar"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:minHeight="?attr/actionBarSize"
        app:theme="@style/ThemeOverlay.AppCompat.ActionBar" />

    <include
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_below="@+id/toolbar"
        layout="@layout/toolbar_action_bar_shadow" />

    <TextView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_below="@+id/toolbar"
        android:text="@string/hello_world" />

</RelativeLayout>

res/layout/toolbar_action_bar_shadow.xml

<?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:foreground="?android:windowContentOverlay" />

res/layout-v21/toolbar_action_bar_shadow.xml

<?xml version="1.0" encoding="utf-8"?>
<ImageView xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:src="@drawable/msl__action_bar_shadow" />

res/drawable-v21/res/layout/msl__action_bar_shadow.xml

<?xml version="1.0" encoding="utf-8"?>
<layer-list xmlns:android="http://schemas.android.com/apk/res/android" >

    <!-- intended for lollipop and above -->

    <item>
        <shape
            android:dither="true"
            android:shape="rectangle" >
            <gradient
                android:angle="270"
                android:endColor="#00000000"
                android:startColor="#33000000" />

            <size android:height="10dp" />
        </shape>
    </item>

</layer-list>

不完全一样,但很相似。


编辑:我仍然不知道为什么会这样。我认为我在该问题上编写的代码具有误导性,因为要做的就是设置背景。然而,在我正在测试的应用程序上,它仍然没有帮助。我要修复的应用在导航抽屉上方有工具栏。

有一刻我认为这可能是因为我制作了一个自定义工具栏(它从工具栏扩展)并且改变了它的 alpha 值(根据导航抽屉),但即使我使用普通工具栏并禁用所有与 alpha 相关的东西,它仍然不起作用。此外,不仅如此,在一个全新的项目中,我尝试为工具栏设置半透明背景,并根据“setElevation”方法得到阴影。

现在我更难找到导致此问题的原因,因为这似乎不是因为透明度,也不是因为自定义 Toolbar 类...

这是具有工具栏的 Activity 的布局,以防万一这有什么帮助:

<?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent" >

    <android.support.v4.widget.DrawerLayout
        android:id="@+id/activity_main__drawerLayout"
        android:layout_width="match_parent"
        android:layout_height="match_parent" >

        <FrameLayout
            android:id="@+id/activity_main__fragmentContainer"
            android:layout_width="match_parent"
            android:layout_height="match_parent" />

        <include
            android:layout_width="240dp"
            android:layout_height="match_parent"
            android:layout_gravity="left"
            android:layout_marginTop="?attr/actionBarSize"
            layout="@layout/activity_main__sliding_menu" />
    </android.support.v4.widget.DrawerLayout>

    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:orientation="vertical" >

        <com.app.ui.Toolbar
            android:id="@+id/activity_main__toolbar"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:background="?attr/colorPrimary"
            android:layoutDirection="ltr"
            android:minHeight="?attr/actionBarSize"
            app:theme="@style/ThemeOverlay.AppCompat.ActionBar"
            tools:ignore="UnusedAttribute" />

        <!-- <include -->
        <!-- android:layout_width="match_parent" -->
        <!-- android:layout_height="wrap_content" -->
        <!-- layout="@layout/toolbar_action_bar_shadow" /> -->
    </LinearLayout>

</FrameLayout>

【问题讨论】:

标签: android android-actionbar android-support-library android-elevation


【解决方案1】:

这是我在我的一个应用程序中所做的,它显示了阴影(人造阴影):

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
        android:id="@+id/mainActivityLinearLayout"
        android:layout_width="match_parent"
        android:orientation="vertical"
        android:layout_height="match_parent"
        android:background="@drawable/logo">

      <LinearLayout
        android:layout_height="?attr/actionBarSize"
        android:layout_width="match_parent"
        android:orientation="vertical">

        <!-- refer to your toolbar layout -->
        <include layout="@layout/toolbar"/>

      </LinearLayout>

      <!-- My Left Drawer -->
      <android.support.v4.widget.DrawerLayout
        android:id="@+id/drawer_layout"
        android:layout_width="match_parent"
        android:layout_height="match_parent"    >

        <RelativeLayout
            xmlns:android="http://schemas.android.com/apk/res/android"
            android:id="@+id/relative_layout"
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:layout_marginStart="0dp"
            android:layout_marginLeft="0dp" >

           ....

           <!-- Lots of other stuffs -->             

           ....

           <!-- Shadow -->
          <View
           android:layout_width="match_parent"
           android:layout_below="@+id/toolbarShadow"
           android:layout_marginTop="0dp"
           android:layout_height="6dp"
           android:background="@drawable/toolbar_dropshadow" />

        </RelativeLayout>
     </android.support.v4.widget.DrawerLayout>


 </LinearLayout>

toolbar_dropshadow.xml:

<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item>
    <shape>
        <gradient
            android:angle="90"
            android:startColor="@android:color/transparent"
            android:endColor="#D6D6D6"
            android:type="linear" />
    </shape>
</item>
</selector>

我正在使用地图活动,所有这些都在我的地图视图上显示出美妙的阴影。

希望这会有所帮助...

【讨论】:

  • 好吧,我在我发布的代码上做了同样的事情。我希望看看如何在 Lollipop 上使用普通的,并知道是什么原因导致它看起来不太好。
  • 由于某种原因(可能是一个错误),如果您在棒棒糖设备上使用设置高度,请确保您没有设置具有透明度的纯色,例如:#eeff0000,高度阴影确实不显示,而是使用 : #ff0000 进行正确使用。此外,带有 alpha 的背景颜色似乎也不起作用。使用不带 alpha 的背景颜色。如果您的影子仍然无法按预期工作,请发布您正在使用的棒棒糖代码,我可能会提供帮助。希望这会有所帮助...
  • 查看我的编辑。可悲的是,事实并非如此,在一个新项目中,我实际上成功地使用了半透明的背景。现在我更难找到原因了。
【解决方案2】:

据我所知/可以阅读,AppCompat 库目前不渲染任何阴影。电话似乎在那里(例如ViewCompat.setElevation(View view, float elevation)),但它似乎没有做任何事情。

所以我猜你现在需要求助于添加自己的阴影,至少在支持库实现阴影渲染之前是这样。

查看 Google IO 2014 源代码,他们的实现是这样的:

  • DrawShadowFrameLayout 可以将背景绘制为阴影
  • bottom_shadow.9.png 表示操作栏下方的阴影
  • app:shadowDrawable 属性设置阴影可绘制
  • DrawShadowFrameLayout 上的 setShadowTopOffset() 将阴影向下移动,因此它很好地显示在操作栏下方。 (您需要自己设置)

有关此Reddit Threadstackoverflow 的更多信息。

【讨论】:

  • 他们为什么使用“DrawShadowFrameLayout”?他们会在某些情况下隐藏阴影吗?
  • 是的,他们确实根据 values/refs.xml 中的引用选择了可绘制的阴影,并且该引用是 api 级别 21 的 @null。
  • 我的意思是,他们为什么要使用这个类?它有一个隐藏阴影的选项......他们可以根据资源设置可见性/可绘制性。
  • 不确定他们为什么使用setShadowVisible 方法,但我猜这与滚动后隐藏阴影有关...使用DrawShadowFrameLayout 有两个优点:1. 他们可以使用棒棒糖的布局与旧 api 的完全相同(DrawShadowFrameLayout 巧妙地隐藏了所有实现细节) 2. 这个类可以潜在地用于更多类型的阴影(例如 cardview -> 侧面 + 底部阴影),只需注入不同的 9 -补丁
  • 我明白了。我仍然不明白为什么在我的小测试中一切似乎都运行良好,但在应用程序上却没有。无论如何,所以您的建议是使用可绘制对象,仅此而已,这就是我在解决方法中所做的,对吧?
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2014-12-29
  • 1970-01-01
  • 2013-08-19
  • 1970-01-01
  • 2015-01-15
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多