Appcompat v21工具栏在Lollipop之前的高度问题

45

首先,我知道这个问题之前已经被问过了,但之前没有得到答案。希望有人能给我一个答案。

在我的应用程序中,我使用了来自Appcompat_v7(API 21)的工具栏。这是我的代码:

<android.support.v7.widget.Toolbar
    style="@style/DarkActionbarStyle"
    android:id="@+id/toolBar"
    android:layout_width="match_parent"
    android:layout_height="@dimen/actionbar_height" />

这是我使用的工具栏样式:

<style name="DarkActionbarStyle" parent="@style/Widget.AppCompat.Toolbar">
    <item name="android:background">?attr/colorPrimary</item>
    <item name="titleTextAppearance">@style/ActionBarTitle</item>
    <item name="android:elevation">2dp</item>
    <item name="popupTheme">@style/ThemeOverlay.AppCompat.Light</item>
    <item name="theme">@style/ThemeActionBarDark</item>
</style>

<style name="ThemeActionBarDark" parent="@style/ThemeOverlay.AppCompat.Dark.ActionBar">
    <item name="actionBarItemBackground">@drawable/btn_dark_orange</item>
    <item name="selectableItemBackground">@drawable/btn_dark_orange</item>
</style>

问题是,高度在Lollipop之前无法使用。所以我的问题是:是否有可能在Lollipop之前的设备上在工具栏下面添加阴影?

9个回答

74

这对我非常有效:

<android.support.v7.widget.CardView
    xmlns:card_view="http://schemas.android.com/apk/res-auto"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:background="@color/primary"
    card_view:cardElevation="4dp"
    card_view:cardCornerRadius="0dp">

    <android.support.v7.widget.Toolbar
        android:id="@+id/toolbar"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:background="@color/primary"
        android:minHeight="?attr/actionBarSize" />

</android.support.v7.widget.CardView>

这对我在API 22上运行良好,但在API 21上不行(我的minSdk是19)。我正在使用与您相同的代码。无论如何,我的应用程序主题继承自Theme.AppCompat.Light.NoActionBar。我不知道这可能是错误的原因。有什么想法吗?(我刚开始进行Android开发)。 - link
2
已修复。对于在Lollipop之前的版本中遇到工具栏边距问题的用户,请参考此已接受的答案:https://dev59.com/x14c5IYBdhLWcg3w1dPx#P5MToYgBc1ULPQZFn90l - Eduardo Lino
解决方案无效。请参见http://imgur.com/dQa6NJj。我认为我们必须重写AppBarLayout以添加阴影。 - Trancer

18

在工具栏中使用 CardView 容器是不好的选择。

特别是对于低端设备,CardView 很重。

最好的方式是在工具栏下方放置一个渐变阴影视图。阴影视图必须直接作为协调布局的子项存在。也就是说,包含工具栏和阴影视图的 AppBar 必须是兄弟元素。

将此视图组件添加到您的布局中。

 <View
    android:id="@+id/gradientShadow"
    android:layout_width="match_parent"
    android:layout_height="5dp"
    android:background="@drawable/toolbar_shadow"
    app:layout_behavior="@string/appbar_scrolling_view_behavior"
    app:layout_collapseMode="pin"/>

可绘制的toolbar_shadow.xml

<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android"
   android:shape="rectangle">
<gradient
    android:angle="90"
    android:endColor="#33333333"
    android:startColor="@android:color/transparent"/>
</shape>

这将解决早期版本的设备中的问题。但是我们不希望在Lollipop及以上版本的设备中出现阴影,因此在Lollipop及以上版本的设备中将其可见性设置为gone。

if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
        findViewById(R.id.gradientShadow).setVisibility(View.GONE);
}

完成。


您可以在xml中禁用AppBar布局的提升(elevation)以使用渐变(gradient)来适配所有版本。android:stateListAnimator="@null" - Akexorcist

12
您可以使用带有 foreground="?android:windowContentOverlay"FrameLayout 将阴影(高程)添加回去。 在Lollipop之前不支持 elevation 属性。 因此,如果您正在像片段容器一样使用 FrameLayout,只需将 foreground 属性添加到其中即可。

在尝试了其他答案后,我最终选择了这种方式。不过这种方法只适用于FrameLayout,但是有一些方法可以扩展RelativeLayout并使用前景:https://gist.github.com/shakalaca/6199283 - Tristan Vanderaerden
如果您的情况不使用片段和FrameLayout,则应将ImageView放在工具栏正下方,并为其提供阴影可绘制项,例如使用@Alessandro Roaro的答案,并从此链接创建阴影可绘制项:https://dev59.com/deo6XIcBkEYKwwoYIAcL - Stoycho Andreev
在所有地方使用"?android:windowContentOverlay"似乎更加一致。我不喜欢混合两种方法。 我的布局中几乎到处都有片段,所以这不是真正的问题。 - Tristan Vanderaerden
这似乎是解决此问题的方案。但是阴影看起来不太好,也不够逼真。请参见Pre-Lollipop和Marshmallow的图片:http://imgur.com/tyIWMUJ - Trancer

7
作为CardView小部件方法存在问题,我已经使用@Sniper提到的FrameLayout方法,现在它正在完美地工作! 我只想分享您需要使用的代码片段。 将其直接放在工具栏下面,其中包含主要内容:
<FrameLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:foreground="?android:windowContentOverlay">

不要忘记使用以下代码结束:

</FrameLayout>

6
可以生成真实的阴影 - 动画和生成。Lollipop 使用的方法自 Froyo 以来就可用了。我猜在 Honeycomb 中使用的硬件加速也可用于阴影生成。以下是它的工作原理:
- 使用 LightingColorFilter 设置为 0,0 将视图绘制到离屏位图上 - 使用 ScriptIntrinsicBlur 类模糊黑色形状(离屏位图),模糊半径为高度值 - 在视图下方绘制位图
这需要添加自定义高度属性、能够渲染阴影的自定义视图,以及使用渲染脚本和兼容库(适用于旧设备)。我不会深入讨论细节,因为其中有很多问题,包括编译问题和轻微的性能优化。但这是可能的。
为什么官方支持库中没有阴影?
- 它需要更改 UI 框架,因为无法自由地在视图边界外绘制 - 平滑动画需要相当好的 GPU
请参见:

5

我正在使用这个答案

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

<android.support.v7.widget.Toolbar xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@+id/toolbar"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:background="@color/orange"
    android:titleTextAppearance="@color/White"
    app:theme="@style/ThemeOverlay.AppCompat.Dark.ActionBar" />

    <View
        android:layout_width="match_parent"
        android:layout_height="5dp"
        android:background="@drawable/toolbar_shadow" />
</LinearLayout>

toolbar_shadow.xml:

<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android">
    <gradient
        android:startColor="#3f3f3f"
        android:endColor="@android:color/transparent"
        android:angle="270" />
</shape>

4

在API 21(Android Lollipop)之前,您无法使用高程属性。但是,您可以通过编程方式添加阴影,例如使用放置在Toolbar下方的自定义视图。

例如:

<ImageView
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_below="@+id/toolbar"
        android:background="@drawable/shadow"/>

阴影是一个具有黑色渐变的可绘制对象。


1
这似乎是在工具栏下添加阴影的唯一方法。但我私下里希望有另一种解决方案:p - Tristan Vanderaerden
同样,支持API中的CardView实现使用通过编程创建的阴影来复制阴影效果。 - Alessandro Roaro

2
为了在您的工具栏下显示阴影,请使用Google Android Design支持库中提供的AppBarLayout。以下是如何使用它的示例。
<android.support.design.widget.AppBarLayout
            android:layout_width="match_parent"
            android:layout_height="wrap_content">
   <android.support.v7.widget.Toolbar
            android:layout_height="?attr/actionBarSize"
            android:layout_width="match_parent"/>
     </android.support.design.widget.AppBarLayout>

为了使用Google Android Design Support库,请将以下内容输入到您的build.gradle文件中:
 compile 'com.android.support:design:22.2.0'

15
为什么这个答案会被点赞?原帖问的是在Lollipop之前如何提升AppBarLayout,而这个答案并没有在早期版本的设备上提升AppBarLayout,只是在5.0及以上的设备上添加了一个提升的效果。 - Yani2000

1

如果没有操作栏菜单,手动添加阴影的解决方案将起作用。如果有,阴影视图将在操作栏图标之前停止。

我认为更容易的方法是使用垂直线性布局,顶部带有应用程序栏,下面是一个用于阴影的视图,作为下一个线性布局项或在我的情况下。

<LinearLayout Vertical> 
  <v7 toolbar/>
  <RelativeLayout>
     <View for shadow with alignParent_top= true/>
      ....
  </RelativeLayout>
</LinearLayout>

我真的希望在不久的将来,appCompat能够解决这个问题。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接