Добавить высоту/тень на панели инструментов для устройств с предварительным леоптипом
Я обновил приложение для Android в новом материале, но я также хотел добавить тень или возвышение на панель инструментов. Кажется, есть некоторые (хакерские) способы сделать это с помощью изображений/9-патчей, но мне интересно, можно ли это сделать через библиотеки поддержки. (так же, как CardView
может иметь возвышение)
В соответствии с этим ответьте на другой вопрос, это возможно, обернув 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 и через код, но это тоже не работает.
Любая помощь будет оценена! Спасибо заранее.
Update:
Так как я включаю макет панели инструментов в другие макеты, ниже приведен один из моих основных макетов:
<?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>
Ответы
Ответ 1
Для Android 5.0 и выше: AppBarLayout автоматически предоставляет/дает тень в макете.
Вы также можете увеличить высоту AppBarLayout на app:elevation="4dp"
.
Для Pre-Lollipop: вы можете использовать следующую ссылку: https://github.com/vipulasri/Toolbar-Elevation-Pre-Lollipop
Примечание. Панель инструментов также поддерживает возвышение к ней, используя android:elevation="4dp"
Новое обновление: В Appcompat v24.0.0 вы не можете установить возведение в AppBarLayout с помощью setElevation()
и app:elevation
, поскольку они устарели.
Вы должны использовать свойство stateListAnimator
для установки высоты теперь.
Примечание: установите длительность 1 мс в stateListAnimator
, чтобы избежать задержки в чертеже высот.
Замена замещения AppBarLayout задерживается на appCompat v24.0.0
appbar_always_elevated.xml в папке аниматор-v21 в каталоге res.
<?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>
Ответ 2
Попробуйте использовать 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>
Toolbar.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" />
Ответ 3
использовать файл сборки:
compile 'com.android.support:cardview-v7:23.1.1'
ссылается на эту ссылку
для вызова в xml
добавить:
app:cardElevation="8dp"
app:cardCornerRadius="8dp"
app:contentPadding="5dp"
Ответ 4
У меня есть CollapsingToolbarLayout
с Toolbar
и панель инструментов 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);
}
}
Управляй как хочешь. Он покажет градиент на устройствах до Lollipop и покажет нормальную тень для Android 5. 0+.
Ответ 5
Я думаю, что лучшее решение - поместить градиентную тень под панелью инструментов и управлять видимостью, зависит от устройства 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);
}
Ответ 6
Я тоже потерял 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());
Не забудьте добавить панель инструментов в макеты и установить ее с помощью android:id="@id/toolbar"
. Если вы хотите использовать другой идентификатор, вы можете настроить контроллер и добавить другой метод 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" />
Я надеюсь, что это поможет решить вашу проблему. Также обратите внимание, что это может быть оптимизировано еще больше, но оно работает для меня, и я не хочу больше терять время на эту проблему.
Ответ 7
Простое решение при использовании CoordinatorLayout
состоит в том, чтобы закрепить ImageView
"тенью" чуть ниже AppBarLayout
или Toolbar
. Это даже работает с 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
, который будет использоваться только на устройствах, предшествующих Lollipop:
<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>
Ответ 8
Использовать CardView
<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>