【问题标题】:Add elevation/shadow on toolbar for pre-lollipop devices在棒棒糖前设备的工具栏上添加高程/阴影
【发布时间】:2015-09-15 21:46:56
【问题描述】:

我将我的 android 应用程序更新为新的材料设计,但我还想为工具栏添加一些阴影或高度。似乎有一些(hacky)方法可以通过 images/9-patches 来实现,但我想知道它是否可以通过支持库来实现。 (就像CardView 可以有海拔)

根据this 对另一个问题的回答,这可以通过将Toolbar 包装在AppBarLayout 中来实现,但这对我不起作用。

我的布局:

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

我也尝试通过 XML 和代码设置海拔,但这也不起作用。

任何帮助将不胜感激!提前致谢。

更新:

由于我将工具栏布局包含在其他布局中,因此以下是我的主要布局之一:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:orientation="vertical"
    android:layout_width="match_parent"
    android:layout_height="match_parent">
    <include
        layout="@layout/Toolbar" />
    <fragment
        class="OverAllField.XamarinAndroid.Fragments.Planning.PlanningFragment"
        android:id="@+id/PlanningFragment"
        android:layout_width="match_parent"
        android:layout_height="0dp"
        android:layout_weight="1" />
</LinearLayout>

【问题讨论】:

  • 您是否使用 标签将其包含在您的活动布局中?如果是,请发布您的活动布局。
  • @BinoyBabu 是的,我使用包含标签。我用活动布局更新了我的答案。感谢您的宝贵时间。

标签: android xamarin.android material-design android-toolbar


【解决方案1】:

尝试在活动布局中使用 AppBarLayout。试试:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:orientation="vertical"
    android:layout_width="match_parent"
    android:layout_height="match_parent">

    <android.support.design.widget.AppBarLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content">

        <include
            layout="@layout/Toolbar" />
    </android.support.design.widget.AppBarLayout>

    <fragment
        class="OverAllField.XamarinAndroid.Fragments.Planning.PlanningFragment"
        android:id="@+id/PlanningFragment"
        android:layout_width="match_parent"
        android:layout_height="0dp"
        android:layout_weight="1" />
</LinearLayout>

工具栏.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"
    android:id="@+id/Toolbar"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:minHeight="?attr/actionBarSize"
    android:background="?attr/colorPrimary"
    android:theme="@style/ThemeOverlay.AppCompat.Dark.ActionBar"
    app:popupTheme="@style/ThemeOverlay.AppCompat.Light" />

【讨论】:

  • 在我的情况下也没有显示阴影。如果有帮助,我正在使用带有 android 4.4.4 KitKat 的手机。谢谢
  • 那我就不知所措了。我认为您可能必须在片段前景中为 pre lollipop 使用投影。
  • 好的,奇怪的是它对你有用。也许它与我使用 Xamarin 有关,它只适用于本机支持库......然后我会看看其他解决方案。无论如何感谢您的帮助,不胜感激。
  • @avb1994 我有同样的问题,我也在使用 Xamarin。所以这很可能是一个 Xamarin 问题。 :-(
【解决方案2】:

对于 Android 5.0 及更高版本:AppBarLayout 自动在布局中提供/赋予阴影。 您还可以通过app:elevation="4dp" 增加AppBarLayout 的高度。

对于 Pre-Lollipop :您可以使用以下链接:https://github.com/vipulasri/Toolbar-Elevation-Pre-Lollipop

注意:工具栏也支持提升,使用android:elevation="4dp"


新更新:Appcompat v24.0.0 中,您不能使用 setElevation()app:elevation 将高度设置为 AppBarLayout,因为它们已被弃用。

您现在必须使用stateListAnimator 属性来设置海拔。

注意:在StateListAnimator 中将持续时间设置为 1ms,以便避免立面图延迟

AppBarLayout elevation change is delayed on appCompat v24.0.0

appbar_always_elevated.xmlres 目录下的 animator-v21 文件夹中。

<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item>
    <objectAnimator android:propertyName="elevation"
                    android:valueTo="8dp" 
                    android:valueType="floatType"
                    android:duration="1"/>
</item>
</selector>

在 AppbarLayout 中:

<android.support.design.widget.AppBarLayout
        android:layout_width="match_parent"
        android:layout_height="300dp"
        android:fitsSystemWindows="true"
        android:stateListAnimator="@animator/appbar_always_elevated"
        android:theme="@style/AppTheme.AppBarOverlay">

</android.support.design.widget.AppBarLayout>

【讨论】:

  • 添加 app:elevation 在棒棒糖之前对我不起作用,无论是添加到 AppBarLayout 还是工具栏
  • @oli.G 在这种情况下你必须使用第二个选项。
  • 那个链接太棒了。 +1
  • 如果您将此链接应用于具有列表的活动的工具栏,则该链接不是很有用。当您开始向下滚动时,“阴影”会完全隐藏项目,当您“过度滚动”到顶部时,会完全取代顶部的突出显示颜色。不好。
【解决方案3】:

我在这个问题上也浪费了 1 天的时间,但我终于想出了一个办法。

/**
 * Controller for the toolbar which will take care of the drop down shadow also on pre-lollipop devices.
 * <br/>
 * The controller also handles the status bar based on the state of the toolbar.
 * <p/>
 * Created by <b>Negru Ionut Valentin</b> on <b>20/1/2016</b>.
 */
public class ToolbarController {

    private boolean handleStatusBar = false;
    private boolean showTitle = true;

    /**
     * Call this method in onCreate() method of your Activity or in onCreateView() in Fragment
     *
     * @param view
     *         The view into which to look for the toolbar
     * @param activity
     *         The activity for which setup the toolbar
     *
     * @return The toolbar found and customized or {@code null}
     */
    public Toolbar initToolbar(View view, Activity activity) {
        Toolbar mToolbar = (Toolbar) view.findViewById(R.id.toolbar);

        // Valid and visible toolbar - otherwise ignore
        if (null != mToolbar && mToolbar.getVisibility() == View.VISIBLE) {

            int paddingLeft = mToolbar.getPaddingLeft();
            int paddingRight = mToolbar.getPaddingRight();
            int paddingBottom = mToolbar.getPaddingBottom();
            // Set the top padding of the toolbar to match the status bar height
            int paddingTop = new CynnyContextWrapper(activity).getStatusBarHeight();

            mToolbar.setPadding(paddingLeft, paddingTop, paddingRight, paddingBottom);

            if (Build.VERSION.SDK_INT <= Build.VERSION_CODES.LOLLIPOP) {
                ViewParent parent = mToolbar.getParent();
                if (parent instanceof RelativeLayout) {
                    // Manually create the drop shadow
                    RelativeLayout.LayoutParams params =
                            new RelativeLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT,
                                                            Metrics.convertDpToPixel(4, activity));

                    View dropShadow = new View(activity);
                    dropShadow.setBackgroundResource(R.drawable.toolbar_shadow);

                    params.addRule(RelativeLayout.BELOW, R.id.toolbar);

                    ((RelativeLayout) parent).addView(dropShadow, params);
                }
            }

            if (activity instanceof AppCompatActivity) {
                // Check if the Activity actually support ActionBar with Toolbar and set our custom Toolbar for it
                ((AppCompatActivity) activity).setSupportActionBar(mToolbar);

                // Get the actionbar from the activity
                ActionBar actionBar = ((AppCompatActivity) activity).getSupportActionBar();
                if (null != actionBar) {
                    // If the actionbar is valid, customize it
                    actionBar.setDisplayHomeAsUpEnabled(true);
                    actionBar.setHomeButtonEnabled(true);

                    actionBar.setDisplayShowTitleEnabled(this.showTitle);

                    mToolbar.setNavigationIcon(R.drawable.ic_arrow_back_selector);
                }
            }

            if (this.handleStatusBar) {
                // For showing the status bar
                activity.getWindow().clearFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN);
                activity.getWindow().addFlags(WindowManager.LayoutParams.FLAG_FORCE_NOT_FULLSCREEN);
            }
        } else if (handleStatusBar) {
            // Force hide the status bar
            activity.getWindow().addFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN);
            activity.getWindow().clearFlags(WindowManager.LayoutParams.FLAG_FORCE_NOT_FULLSCREEN);
        }

        return mToolbar;
    }

    /**
     * Set the flag indicating if the controller should handle or not the status bar.
     *
     * @param handleStatusBar
     *         Flag which indicates if the initialization of the toolbar should also update
     *         the status bar state (if two calls are made for the init, the last one will
     *         be taken into consideration).
     *
     * @return The current toolbar controller.
     */
    public ToolbarController setHandleStatusBar(boolean handleStatusBar) {
        this.handleStatusBar = handleStatusBar;

        return this;
    }

    /**
     * Set the flag indicating if the toolbar should show or hide the title.
     *
     * @param showTitle
     *         Flag indicating if the toolbar should also show the title (the title can be changed after the toolbar
     *         initialization)
     *
     * @return The current toolbar controller.
     */
    public ToolbarController setShowTitle(boolean showTitle) {
        this.showTitle = showTitle;

        return this;
    }
}

在活动中你应该像这样在 onCreate() 方法中使用它:

// Create and customize the Toolbar controller
new ToolbarController().setHandleStatusBar(true).setShowTitle(true)
                                 .initToolbar(((ViewGroup) findViewById(android.R.id.content)).getChildAt(0),
                                              this);

在片段中你应该像这样在 onCreateView() 方法中使用它:

new ToolbarController().setHandleStatusBar(false).setShowTitle(false).initToolbar(resultView, getActivity());

不要忘记在布局中添加您的工具栏并将其 id 设置为android:id="@id/toolbar"。如果你想使用另一个 id,你可以自定义控制器并添加另一个使用你提供的 id 的 setter 方法。

我创建了两个工具栏布局:

v21

    <!-- This is the new widget added in Lollipop - use with care -->
    <android.support.v7.widget.Toolbar
            android:id="@id/toolbar"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:minHeight="?attr/actionBarSize"
            android:theme="@style/TitleToolbarTheme"
            android:background="?android:attr/colorPrimary"
            android:elevation="@dimen/toolbar_elevation"
            />
</merge>

其他

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

    <!-- This is the new widget added in Lollipop - use with care -->
    <android.support.v7.widget.Toolbar
            android:id="@id/toolbar"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:minHeight="?attr/actionBarSize"
            android:theme="@style/TitleToolbarTheme"
            android:background="?attr/colorPrimary"
            />

</merge>

我在可能的布局中使用它们:

<include layout="@layout/toolbar" />

我希望这将有助于解决您的问题。另请注意,这可以进一步优化,但它对我有用,我不想再在这个问题上浪费时间了。

【讨论】:

  • 代码示例中的toolbar_shadow 是什么。
  • 这是一个9patch的可绘制资源。
【解决方案4】:

使用构建文件:


compile 'com.android.support:cardview-v7:23.1.1'

refer this link

调用xml 添加:

app:cardElevation="8dp"
app:cardCornerRadius="8dp"
app:contentPadding="5dp"

【讨论】:

    【解决方案5】:

    使用卡片视图

       <android.support.v7.widget.CardView
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:gravity="top"
        app:cardCornerRadius="0dp">
    
        <android.support.design.widget.AppBarLayout
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:theme="@style/AppTheme.AppBarOverlay">
    
    
            <android.support.v7.widget.Toolbar
                android:id="@+id/toolbar"
                android:layout_width="match_parent"
                android:layout_height="?attr/actionBarSize"
                app:popupTheme="@style/AppTheme.PopupOverlay" />
        </android.support.design.widget.AppBarLayout>
    </android.support.v7.widget.CardView>
    

    【讨论】:

    • 嘿丽娜,你能解释一下你建议的改变是什么吗?为什么它会解决问题?
    • 提升pre-lolipop设备中的appbar用cardview包围它,并根据需要提升cardview。这将提升应用栏和阴影将自动给出@liorsolomon
    • 这是我见过的最糟糕的解决方案。
    【解决方案6】:

    我认为最好的解决方案是在工具栏下方放置一个渐变阴影视图,并根据设备 sdk 进行可见性操作。

    toolbar.xml

     <?xml version="1.0" encoding="utf-8"?>
        <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
            xmlns:app="http://schemas.android.com/apk/res-auto"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:orientation="vertical">
    
            <android.support.v7.widget.Toolbar xmlns:android="http://schemas.android.com/apk/res/android"
                xmlns:app="http://schemas.android.com/apk/res-auto"
                android:id="@+id/toolbar"
                android:layout_width="match_parent"
                android:layout_height="?attr/actionBarSize"
                android:background="@android:color/white"
                android:fitsSystemWindows="true"
                app:popupTheme="@style/AppTheme.PopupOverlay">
    
                <TextView
                    android:id="@+id/centerTitleToolbarTextView"
                    android:layout_width="match_parent"
                    android:layout_height="match_parent"
                    android:gravity="center"
                    android:maxLines="1"
                    android:textColor="@color/color_toolbar"
                    android:textSize="@dimen/titleToolbar" />
    
            </android.support.v7.widget.Toolbar>
    
            <View
                android:id="@+id/shadow_view"
                android:layout_width="match_parent"
                android:visibility="gone"
                android:layout_height="4dp"
                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="#c1c1c1"
            android:centerColor="#e6e6e6"
            android:endColor="#f1f1f1"
            android:angle="270" />
    </shape>
    

    MainActivity.class

    if (Build.VERSION.SDK_INT < Build.VERSION_CODES.LOLLIPOP) {
            findViewById(R.id.shadow_view).setVisibility(View.VISIBLE);
          }
    

    【讨论】:

      【解决方案7】:

      我有一个带有ToolbarCollapsingToolbarLayout 和一个类似工具栏的View,它可以上下移动,但位于NestedScrollView 上方,就像https://github.com/k0shk0sh/CoordinatorLayoutExample 一样。 我尝试了很多变种。有时阴影在带有 NestedScrollView 的屏幕上方滚动,有时工具栏会绘制一个没有透明度的实心阴影,有时阴影会出现锯齿。无论如何,这是我的解决方案。

      说,你有一个布局:

      <android.support.design.widget.CoordinatorLayout>
          <android.support.design.widget.AppBarLayout>
               <android.support.design.widget.CollapsingToolbarLayout>
                   <android.support.v7.widget.Toolbar>
                       <!-- Toolbar views if needed -->
                   </android.support.v7.widget.Toolbar>
              </android.support.design.widget.CollapsingToolbarLayout>
          </android.support.design.widget.AppBarLayout>
      
          <!-- Footer Toolbar views if needed -->
      
          <android.support.v4.widget.NestedScrollView
              android:layout_width="match_parent"
              android:layout_height="match_parent"
              app:layout_behavior="@string/appbar_scrolling_view_behavior">
      
              <LinearLayout>
                  <!-- Views -->
              </LinearLayout>
      
          </android.support.v4.widget.NestedScrollView>
      
          <!-- Add this view. It draws a shadow and aligns top of NestedScrollView -->
          <!-- Set visibility to gone or visible -->
          <View
              android:id="@+id/scroll_shadow"
              android:layout_width="match_parent"
              android:layout_height="4dp"
              android:background="@drawable/shadow"
              android:visibility="gone"
              app:layout_behavior="@string/appbar_scrolling_view_behavior" />
      
      </android.support.design.widget.CoordinatorLayout>
      

      添加阴影(drawable/shadow.xml):

      <?xml version="1.0" encoding="utf-8"?>
      <shape xmlns:android="http://schemas.android.com/apk/res/android">
          <gradient
              android:angle="90"
              android:endColor="#ffcccccc"
              android:startColor="#00cccccc" />
      </shape>
      

      添加此方法。这里 scrollShadow 是一个名为“scroll_shadow”的视图:

      private void setShadowVisibility(int visibility) {
          if (Build.VERSION.SDK_INT < Build.VERSION_CODES.LOLLIPOP) {
              scrollShadow.setVisibility(visibility);
          }
      }
      

      随心所欲地操作它。它将在棒棒糖之前的设备上显示渐变,并在 Android 5.0+ 上显示正常阴影。

      【讨论】:

      • 试过这个方案,适用于RecyclerViewNestedScrollView,静止和移动Toolbar
      【解决方案8】:

      使用CoordinatorLayout 时,一个简单的解决方案是在AppBarLayoutToolbar 正下方使用“阴影”锚定ImageView。这甚至适用于CollapsingToolbarLayout,并且正确呈现在“内容”之上:

      <CoordinatorLayout>
        <AppBarLayout android:id="@+id/app_bar">
          <Toolbar/>
        </AppBarLayout>
        <include layout="@layout/app_bar_shadow"/>
        <!-- your content usually goes here -->
      </CoordinatorLayout>
      

      创建一个res/layout/app_bar_shadow.xml 文件,该文件仅用于棒棒糖之前的设备:

      <ImageView
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:adjustViewBounds="true"
        app:layout_anchor="@+id/app_bar"
        app:layout_anchorGravity="bottom"
        android:layout_gravity="bottom"
        app:srcCompat="@drawable/shadow_app_bar"
        />
      

      创建一个“空”res/layout-v21/app_bar_shadow.xml 文件,用于 Android 5+ 设备:

       <merge/>
      

      最后,一个合适的res/drawable/shadow_app_bar.xml

      <shape>
        <gradient
          android:angle="90"
          android:startColor="#00000000"
          android:endColor="#30000000"
          />
        <size android:height="@dimen/design_appbar_elevation" />
      </shape>
      

      【讨论】:

        猜你喜欢
        • 2016-11-23
        • 2017-01-29
        • 1970-01-01
        • 2015-09-22
        • 1970-01-01
        • 2016-10-14
        • 2015-08-12
        • 2015-06-27
        • 2016-05-02
        相关资源
        最近更新 更多