1.Toolbar介绍
Toolbar是应用程序中使用的标准工具栏。
Toolbar是应用程序布局中使用的Actionbar的泛华,虽然Actionbar是传统Activity的不透明窗口装饰的控制框架的一部分,但是在视图层次里Toolbar可以被任何任意级别的嵌套。使用Toolbar时,应用程序可以通过使用android.support.v7.app.AppCompatActivity的setSupportActionBar()方法来将Toolbar指定为Activity的action bar。
Toolbar比Actionbar支持更多的集中特征设置, 它可以包含以下可选元素的组合:
导航按钮(A navigation button):可以是一个返回箭头,菜单切换,关闭,折叠,完成或者应用程序选择的另一个符号等等。这个按钮应该始终被用于访问Toolbar容器内的其它导航目的地,和它的所指内容或者所指当前上下文。如果要设置导航按钮,那么它在Toolbar的最小高度里是垂直对齐的。
logo图片(A branded logo image):可以任意宽而且可以延生到Toolbar的整个高度。
标题和子标题(A title and subtitle):标题(title)应该是一个标志,它应该表示Toolbar在导航层级中的位置和所包含的内容。如果当前的内容应注明任何扩展信息,那么就可以用子标题(subtitle)。如果应用程序已经用了logo图片,那么应当考虑省略标题和子标题。
一个或者多个自定义视图(One or more custom views):Toolbar可以添加任意的子视图。但如果子视图需要居中显示,只有在其它所有的元素被放置完之后,才能尝试让它在剩下的空间中居中显示。
建议:现在的Android UI 开发人员,应该更注重工具栏视觉上不同的配色方案而不是应用程序的图标,以前的标准布局应用程序图标加标题在API 21以上的设备上不推荐使用。
2.Toolbar的使用
2.1 设置主题(Style)
:
<resources>
<!-- Base application theme. -->
<style name="BaseAppTheme" parent="Theme.AppCompat.Light.NoActionBar">
<!-- toolbar(actionbar)颜色 -->
<item name="colorPrimary">#3F51B5</item>
<!-- 状态栏颜色 -->
<item name="colorPrimaryDark">#2AD4FF</item>
<!-- 窗口的背景颜色 -->
<item name="android:windowBackground">@android:color/white</item>
<!-- 字体颜色-->
<item name="android:textColorPrimary">@android:color/white</item>
</style>
</resources>
这里需要去掉ActionBar(Theme.AppCompat.Light.NoActionBar),才能够设置Toolbar。
res/values-v19/style.xml中:
<resources>
<!-- application theme. -->
<style name="AppTheme" parent="@style/BaseAppTheme">
<item name="android:windowTranslucentStatus">true</item>
<item name="android:windowTranslucentNavigation">false</item>
</style>
</resources>
这里是API 19的设备,让状态栏透明,设置了Toolbar之后,就可以让状态栏一体化,没有让有底部导航栏的设备透明的原因是:在很多4.4系统的设备中,屏蔽了导航栏着色,设置了之后界面会不好看,建议在5.0系统之前不要设置底部导航栏。
在res/values-v21/style.xml中:
<?xml version="1.0" encoding="utf-8"?>
<resources>
<style name="AppTheme" parent="@style/BaseAppTheme">
<item name="android:windowTranslucentStatus">true</item>
<item name="android:windowTranslucentNavigation">true</item>
<item name="android:navigationBarColor">#3F51B5</item>
<item name="android:colorAccent">#3F51B5</item>
</style>
</resources>
在API 21以上的设备可以设置底部导航栏的颜色,使整个界面一体化。
2.2 添加Toolbar
在res/layout/toolbar.xml中:
<?xml version="1.0" encoding="utf-8"?>
<android.support.v7.widget.Toolbar
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/toolbar"
android:clipToPadding="true"
android:layout_height="wrap_content"
android:layout_width="match_parent"
android:minHeight="?attr/actionBarSize"
android:background="?attr/colorPrimary"
app:popupTheme="@style/ThemeOverlay.AppCompat.Light"
app:theme="@style/ThemeOverlay.AppCompat.ActionBar"
android:fitsSystemWindows="true">
</android.support.v7.widget.Toolbar>
将toolbar.xml单独一个布局文件,这样可让整个应用程序的Activity引用。
在res/layout/activity_main.xml中:
<RelativeLayout 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"
tools:context=".MainActivity">
<include layout="@layout/toolbar"/>
</RelativeLayout>
2.3 在Activity中设置Toolbar
public class MainActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);
toolbar.setLogo(R.drawable.ic_launcher);
toolbar.setTitle("Title");
toolbar.setSubtitle("Subtitle");
setSupportActionBar(toolbar);
getSupportActionBar().setDisplayHomeAsUpEnabled(true);
getSupportActionBar().setDefaultDisplayHomeAsUpEnabled(true);
}
@Override
public boolean onCreateOptionsMenu(Menu menu) {
getMenuInflater().inflate(R.menu.menu_main, menu);
return true;
}
@Override
public boolean onOptionsItemSelected(MenuItem item) {
int id = item.getItemId();
switch (id) {
case R.id.action_settings: {
Toast.makeText(this,"Settings",Toast.LENGTH_SHORT).show();
return true;
}
case android.R.id.home: {
finish();
break;
}
}
return super.onOptionsItemSelected(item);
}
}
注意:Activity要继承AppCompatActivity,才能使用Toolbar。
3.自定义Toolbar
在自定义toolbar之前需要注意:”如果子视图需要居中显示,只有在其它所有的元素被放置完之后,才能尝试让它在剩下的空间中居中显示。”
意思如下图所示:
要自定义Toolbar,只需在toolbar.xml中添加子布局就行了:
<?xml version="1.0" encoding="utf-8"?>
<android.support.v7.widget.Toolbar
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/toolbar"
android:clipToPadding="true"
android:layout_height="wrap_content"
android:layout_width="match_parent"
android:minHeight="?attr/actionBarSize"
android:background="?attr/colorPrimary"
app:popupTheme="@style/ThemeOverlay.AppCompat.Light"
app:theme="@style/ThemeOverlay.AppCompat.ActionBar"
android:fitsSystemWindows="true">
<TextView
android:background="#2AD4FF"
android:gravity="center"
android:textSize="18sp"
android:textColor="@android:color/white"
android:text="Title"
android:layout_width="match_parent"
android:layout_height="match_parent"/>
</android.support.v7.widget.Toolbar>
这样自定义的效果并不能达到我们在实际开发中需要的目的,从上面的效果图显示,自定义子布局的宽高只能够占Toolbar的一部分,但 通常我们需要的是填充到整个Toolbar,效果因该如下图所示:
要想到达这样的效果,首先需要在toolbar中添加以下属性:
app:contentInsetLeft="0dp"
app:contentInsetStart="0dp"
app:contentInsetRight="0dp"
app:contentInsetEnd="0dp"
去掉空余空间,然后再在子布局中将高度设置为和toolbar一样的高度,只需添加属性:android:minHeight="?attr/actionBarSize"即可。
附加:通常情况下,应用程序中会有很多Activity,如果有多个Activity需要自定义Toolbar的布局,我们更希望用代码去动态的改变布局,在设置setSupportActionBar(toolbar)完之后,我们可以通过getSupportActionBar().setCustomView()方法来设置,但需要注意的是,每个自定义的toolbar布局文件因该和res/layout/toolbar.xml一样,例如res/layout/titlebar_main.xml:
<?xml version="1.0" encoding="utf-8"?>
<android.support.v7.widget.Toolbar
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:android="http://schemas.android.com/apk/res/android"
android:clipToPadding="true"
android:layout_height="wrap_content"
android:layout_width="match_parent"
android:background="?attr/colorPrimary"
app:popupTheme="@style/ThemeOverlay.AppCompat.Light"
app:theme="@style/ThemeOverlay.AppCompat.ActionBar"
app:contentInsetLeft="0dp"
app:contentInsetStart="0dp"
app:contentInsetRight="0dp"
app:contentInsetEnd="0dp"
android:fitsSystemWindows="true">
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="?attr/actionBarSize">
<ImageView
android:layout_alignParentLeft="true"
android:scaleType="centerInside"
android:src="@drawable/ic_launcher"
android:layout_width="wrap_content"
android:layout_height="match_parent"/>
<TextView
android:layout_centerInParent="true"
android:gravity="center"
android:textSize="16sp"
android:textColor="@android:color/white"
android:text="Title"
android:layout_width="wrap_content"
android:layout_height="wrap_content"/>
</RelativeLayout>
</android.support.v7.widget.Toolbar>
然后在代码中设置为:
getSupportActionBar().setDisplayOptions(ActionBar.DISPLAY_SHOW_CUSTOM);
View view = getLayoutInflater().inflate(R.layout.titlebar_main, null);
getSupportActionBar().setCustomView(view, new ActionBar.LayoutParams(ActionBar.LayoutParams.MATCH_PARENT, ActionBar.LayoutParams.WRAP_CONTENT));
效果如下图所示:
4.继承自Activity使用Toolbar
上面使用Toolbar时,需要继承自AppCompatActivity,但有些情况下,只能继承自Activity,官方文档中提供了一种方法,利用委托,示例代码模板如下:
/*
* Copyright (C) 2014 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.example.android.supportv7.app;
import android.content.res.Configuration;
import android.os.Bundle;
import android.preference.PreferenceActivity;
import android.support.annotation.LayoutRes;
import android.support.annotation.Nullable;
import android.support.v7.app.ActionBar;
import android.support.v7.app.AppCompatDelegate;
import android.support.v7.widget.Toolbar;
import android.view.MenuInflater;
import android.view.View;
import android.view.ViewGroup;
/**
* A {@link android.preference.PreferenceActivity} which implements and proxies the necessary calls
* to be used with AppCompat.
*
* This technique can be used with an {@link android.app.Activity} class, not just
* {@link android.preference.PreferenceActivity}.
*/
public abstract class AppCompatPreferenceActivity extends PreferenceActivity {
private AppCompatDelegate mDelegate;
@Override
protected void onCreate(Bundle savedInstanceState) {
getDelegate().installViewFactory();
getDelegate().onCreate(savedInstanceState);
super.onCreate(savedInstanceState);
}
@Override
protected void onPostCreate(Bundle savedInstanceState) {
super.onPostCreate(savedInstanceState);
getDelegate().onPostCreate(savedInstanceState);
}
public ActionBar getSupportActionBar() {
return getDelegate().getSupportActionBar();
}
public void setSupportActionBar(@Nullable Toolbar toolbar) {
getDelegate().setSupportActionBar(toolbar);
}
@Override
public MenuInflater getMenuInflater() {
return getDelegate().getMenuInflater();
}
@Override
public void setContentView(@LayoutRes int layoutResID) {
getDelegate().setContentView(layoutResID);
}
@Override
public void setContentView(View view) {
getDelegate().setContentView(view);
}
@Override
public void setContentView(View view, ViewGroup.LayoutParams params) {
getDelegate().setContentView(view, params);
}
@Override
public void addContentView(View view, ViewGroup.LayoutParams params) {
getDelegate().addContentView(view, params);
}
@Override
protected void onPostResume() {
super.onPostResume();
getDelegate().onPostResume();
}
@Override
protected void onTitleChanged(CharSequence title, int color) {
super.onTitleChanged(title, color);
getDelegate().setTitle(title);
}
@Override
public void onConfigurationChanged(Configuration newConfig) {
super.onConfigurationChanged(newConfig);
getDelegate().onConfigurationChanged(newConfig);
}
@Override
protected void onStop() {
super.onStop();
getDelegate().onStop();
}
@Override
protected void onDestroy() {
super.onDestroy();
getDelegate().onDestroy();
}
public void invalidateOptionsMenu() {
getDelegate().invalidateOptionsMenu();
}
private AppCompatDelegate getDelegate() {
if (mDelegate == null) {
mDelegate = AppCompatDelegate.create(this, null);
}
return mDelegate;
}
}
这样就与在AppCompatActivity中使用Toolbar一样了。
其实从 AppCompatActivity的源代码中分析,它也是利用AppCompatDelegate来使用support library中的action bar 特性的:
总结:以前的Actionbar已经被淘汰了,Toolbar具有更多的特性,在高版本中,使用Toolbar最好。