Как показать тень панели ActionBar и панели инструментов библиотеки поддержки на всех версиях Android?

Это простой вопрос:

Я использую новую библиотеку поддержки, которая позволяет мне иметь экземпляр панели инструментов и даже устанавливать ее как actionBar активности (или использовать по умолчанию).

Как настроить тень, создаваемую панелью инструментов (или по умолчанию ActionBar)?

Я попытался использовать "setElevation" (на обоих из них), но он ничего не делал на Android Lollipop.

Кроме того, я не могу найти, как настроить тень на версиях до Lollipop. Может быть, API для этого? или, по крайней мере, с возможностью рисования (я не нашел, хотя я и пытался)?


ОК, мне удалось найти следующие вещи:

Для Lollipop и pre-Lollipop, когда ваша активность использует обычные темы AppCompat (например, ThemeAppCompat.Light), тень должна выглядеть хорошо.

Однако, когда вы используете "setSupportActionBar" (и используйте соответствующую тему, например, "Theme.AppCompat.Light.NoActionBar", например), у вас будут проблемы с тенью.

Для pre-Lollipop вы можете поместить 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".

Это уродливое решение, но оно работает, но только для версий до Lollipop.

В любом случае, я все еще не мог найти способ показать тень для Lollipop, если я использую "setSupportActionBar" . Я попытался использовать "setElevation" на панели инструментов и панели действий (используя "getSupportActionBar", сразу после вызова "setSupportActionBar" ).

Я также не понимаю, как получить стандартную высоту панели действий, так как я заметил, что в большинстве учебников говорится, что для панели инструментов используется "minHeight". Поблагодарите также за помощь.

Может ли кто-нибудь помочь мне с этим?

Опять же, чтобы прояснить это, я спрашиваю:

  • для Pre-Lollipop, покажите ту же самую тень, которая используется в библиотеке поддержки как для панели инструментов, так и для ActionBar.
  • То же самое для Lollipop (но используйте тот, который имеет Lollipop)
  • Дополнительно: настроить тень на "Lollipop" (и, возможно, настроить ее на всех версиях).
  • Дополнительно: почему minHeight на панели инструментов получает значение высоты панели действий вместо самой высоты?

EDIT: Хорошо, это до тех пор, пока я сделал это, чтобы имитировать тень Lollipop:

<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>

Рез/макет/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" />

Рез/макет-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/вытяжка-V21/RES/макет/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>

Это не совсем то же самое, но похоже.


EDIT: Я до сих пор не знаю, почему это происходит. Я думаю, что код, который я написал на вопрос, вводит в заблуждение, так как все, что нужно сделать, это установить фон. Тем не менее в приложении, которое я тестирую, все равно не помогает. Приложение, которое я пытаюсь исправить, имеет панель инструментов над ящиком навигации.

На мгновение я подумал, что это может быть потому, что я создал настраиваемую панель инструментов (которая простирается от Панели инструментов) и которая меняет его значение альфа (в соответствии с ящиком навигации), но даже если я использую обычную панель инструментов и отключу все, что связано с альфой, все равно не работает. Кроме того, не только это, но и в совершенно новом проекте, я попытался установить полупрозрачный фон для панели инструментов, и он получил тень в соответствии с методом setElevation.

Теперь мне еще труднее найти причину этой проблемы, потому что это похоже не из-за прозрачности, а из-за нестандартного класса панели инструментов...

Здесь макет действия, в котором есть панель инструментов, в случае, если это может помочь в любом случае:

<?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>

Ответ 1

Насколько я знаю/могу читать, в настоящее время библиотека AppCompat не создает никаких теней. Кажется, что звонки там (например, ViewCompat.setElevation(View view, float elevation)), но он ничего не делает.

Итак, я думаю, вам нужно прибегнуть к добавлению ваших собственных теней на данный момент, по крайней мере, пока библиотека поддержки не реализует рендеринг тени.

Посмотрев исходный код Google IO 2014, они реализованы следующим образом:

  • DrawShadowFrameLayout, который может отображать фоновый рисунок как тень
  • bottom_shadow.9.png, который представляет собой тень под панелью действий
  • app: shadowDrawable для установки теневого рисунка
  • setShadowTopOffset() на DrawShadowFrameLayout сдвигает тень вниз, чтобы она выглядела красиво под панелью действий. (вам нужно установить это самостоятельно)

Подробнее об этом Reddit Thread и fooobar.com/questions/45808/....

Ответ 2

Это то, что я сделал в одном из моих приложений, показывающее тень (искусственная тень):

<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>

Я использую активность карты, и все это показывает прекрасную тень на моем виде карты.

Надеюсь, что это поможет...