在棒棒糖前设备的工具栏上添加高程/阴影
Posted
技术标签:
【中文标题】在棒棒糖前设备的工具栏上添加高程/阴影【英文标题】: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_
android:layout_>
<android.support.v7.widget.Toolbar
android:id="@+id/Toolbar"
android:layout_
android:layout_
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_
android:layout_>
<include
layout="@layout/Toolbar" />
<fragment
class="OverAllField.XamarinAndroid.Fragments.Planning.PlanningFragment"
android:id="@+id/PlanningFragment"
android:layout_
android:layout_
android:layout_weight="1" />
</LinearLayout>
【问题讨论】:
您是否使用尝试在活动布局中使用 AppBarLayout。试试:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_
android:layout_>
<android.support.design.widget.AppBarLayout
android:layout_
android:layout_>
<include
layout="@layout/Toolbar" />
</android.support.design.widget.AppBarLayout>
<fragment
class="OverAllField.XamarinAndroid.Fragments.Planning.PlanningFragment"
android:id="@+id/PlanningFragment"
android:layout_
android:layout_
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_
android:layout_
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.xml 在 res 目录下的 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_
android:layout_
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 @VipulAsri,链接 (blog.grafixartist.com/add-a-toolbar-elevation-on-pre-lollipop) 已损坏。 如果您将此链接应用于具有列表的活动的工具栏,则该链接不是很有用。当您开始向下滚动时,“阴影”会完全隐藏项目,当您“过度滚动”到顶部时,会完全取代顶部的突出显示颜色。不好。【参考方案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_
android:layout_
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_
android:layout_
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_
android:layout_
android:gravity="top"
app:cardCornerRadius="0dp">
<android.support.design.widget.AppBarLayout
android:layout_
android:layout_
android:theme="@style/AppTheme.AppBarOverlay">
<android.support.v7.widget.Toolbar
android:id="@+id/toolbar"
android:layout_
android:layout_
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_
android:layout_
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_
android:layout_
android:background="@android:color/white"
android:fitsSystemWindows="true"
app:popupTheme="@style/AppTheme.PopupOverlay">
<TextView
android:id="@+id/centerTitleToolbarTextView"
android:layout_
android:layout_
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_
android:visibility="gone"
android:layout_
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】:我有一个带有Toolbar
的CollapsingToolbarLayout
和一个类似工具栏的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_
android:layout_
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_
android:layout_
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+ 上显示正常阴影。
【讨论】:
试过这个方案,适用于RecyclerView
和NestedScrollView
,静止和移动Toolbar
。【参考方案8】:
使用CoordinatorLayout
时,一个简单的解决方案是在AppBarLayout
或Toolbar
正下方使用“阴影”锚定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_
android:layout_
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: />
</shape>
【讨论】:
以上是关于在棒棒糖前设备的工具栏上添加高程/阴影的主要内容,如果未能解决你的问题,请参考以下文章