系统原生的ActionBar由于其设计原因,被限定只能位于活动的顶部。Toolbar的强大之处在于,它不仅继承了ActionBar的所有功能,而且灵活性很高。
首先我们都知道,任何一个新建的项目,默认都会显示ActionBar的,这是根据项目中指定的主题来显示的。打开AndroidManifest.xml
<application
android:allowBackup="true"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:roundIcon="@mipmap/ic_launcher_round"
android:supportsRtl="true"
android:theme="@style/AppTheme">
...
application>
可以看到android:theme属性指定了一个AppTheme主题。ctrl+鼠标左键点击AppTheme,会看到如下
<resources>
<style name="AppTheme" parent="Theme.AppCompat.Light.DarkActionBar">
- "colorPrimary"
>@color/colorPrimary
- "colorPrimaryDark">@color/colorPrimaryDark
- "colorAccent">@color/colorAccent
style>
resources>
这里定义了一个叫做AppTheme的主题,然后指定它的parent主题是Theme.AppCompat.Light.DarkActionBar。这个DarkActionBar是一个深色的ActionBar主题。
现在我们准备使用ToolBar来替代ActionBar,需要指定一个不带ActionBar的主题,通常有Theme.AppCompat.Light.NoActionBar和Theme.AppCompat.NoActionBar
Theme.AppCompat.Light.NoActionBar:表示淡色主题,它会将界面的主体颜色设成淡色,陪衬颜色设成深色。
Theme.AppCompat.NoActionBar:表示深色主题,它会将界面的主体颜色设成深色,陪衬颜色设成淡色。
我们这里设置为淡色主题
<resources>
<style name="AppTheme" parent="Theme.AppCompat.Light.NoActionBar">
- "colorPrimary"
>@color/colorPrimary
- "colorPrimaryDark">@color/colorPrimaryDark
- "colorAccent">@color/colorAccent
style>
resources>
接下来看一看如何使用ToolBar
<FrameLayout 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="match_parent">
<androidx.appcompat.widget.Toolbar
android:layout_width="match_parent"
android:layout_height="?attr/actionBarSize"
android:id="@+id/toolbar"
android:background="?attr/colorPrimary"
android:theme="@style/ThemeOverlay.AppCompat.Dark.ActionBar"
app:popupTheme="@style/ThemeOverlay.AppCompat.Light"/>
FrameLayout>
修改标题栏上显示的文字内容 android:label="Psycho"
在AndroidManifest中
<activity
android:name=".MainActivity"
android:label="Psycho">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
intent-filter>
activity>
在ToolBar中添加一些action按钮,右击res->New->Directory,创建一个menu文件夹,在menu文件夹中创建一个toolbar.xml文件,如下
<menu xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto">
<item android:id="@+id/backup"
android:icon="@mipmap/backup"
android:title="Backup"
app:showAsAction="always"
/>
<item android:id="@+id/delete"
android:icon="@mipmap/delete"
android:title="Delete"
app:showAsAction="ifRoom"/>
<item android:id="@+id/settings"
android:icon="@mipmap/seetings"
android:title="Settings"
app:showAsAction="never"/>
menu>
通过< item>标签来定义action按钮,android:icon来设置按钮图片,title设置显示文字,app:showAsAction来设置显示位置
showAsAction有三个属性可以选择,always表示永远显示在toolbar中,如果屏幕空间不够则不显示。ifRoom表示屏幕空间足够的情况下显示在toolbar中,不够的话就会显示在菜单中。never表示永远显示在菜单中。
然后在activity中重写onCreateOptionsMenu方法和onOptionsItemSelected方法
public boolean onCreateOptionsMenu(Menu menu) {
getMenuInflater().inflate(R.menu.toolbar,menu);
return true;
}
@Override
public boolean onOptionsItemSelected(@NonNull MenuItem item) {
switch(item.getItemId()){
case R.id.backup:
Toast.makeText(this, "You clicked backup", Toast.LENGTH_SHORT).show();
break;
case R.id.delete:
Toast.makeText(this, "You clicked delete", Toast.LENGTH_SHORT).show();
break;
case R.id.settings:
Toast.makeText(this, "You clicked settings", Toast.LENGTH_SHORT).show();
break;
default:
}
return true;
}
在onCreateOptionsMenu方法中加载了toolbar.xml菜单文件,然后在onOptionsItemSelected方法中处理每个按钮的点击事件
DrawerLayout是一个布局,在布局中允许放入两个直接子控件,第一个控件是主屏幕中显示的内容,第二个子控件是滑动菜单中显示的内容
<androidx.drawerlayout.widget.DrawerLayout 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="match_parent"
android:id="@+id/drawer_layout">
<FrameLayout
android:layout_width="match_parent"
android:layout_height="match_parent">
<androidx.appcompat.widget.Toolbar
android:layout_width="match_parent"
android:layout_height="?attr/actionBarSize"
android:id="@+id/toolbar2"
android:background="?attr/colorPrimary"
android:theme="@style/ThemeOverlay.AppCompat.Dark.ActionBar"
app:popupTheme="@style/ThemeOverlay.AppCompat.Light">
androidx.appcompat.widget.Toolbar>
FrameLayout>
<TextView
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_gravity="start"
android:text="This is menu"
android:textSize="30sp"
android:background="#fff"/>
androidx.drawerlayout.widget.DrawerLayout>
第二个直接子控件中的layout_gravity属性是必须的,因为我们要告诉滑动菜单是从左往右滑出,还是从右往左,left表示从左往右,right表示从右往左,start表示根据系统语言判断。
然后我们在ToolBar中最左边加入一个导航按钮,来提示用户滑动菜单。
ActionBar actionBar = getSupportActionBar();
drawerLayout = findViewById(R.id.drawer_layout);
if(actionBar!=null){
actionBar.setDisplayHomeAsUpEnabled(true);
actionBar.setHomeAsUpIndicator(R.mipmap.menu);
}
public boolean onOptionsItemSelected(@NonNull MenuItem item) {
switch(item.getItemId()){
case android.R.id.home:
drawerLayout.openDrawer(GravityCompat.START);
break;
}
return true;
}
implementation 'com.android.support:design:28.0.0'
implementation 'de.hdodenhof:circleimageview:2.1.0'
打开app/build.gradle文件,在dependencies闭包中添加上面内容
在使用NavigationView之前,我们还需准备menu和headerLayout,menu是用来在NavigationView显示具体的菜单项,headerLayout是用来在NavigationView显示头布局的
<menu xmlns:android="http://schemas.android.com/apk/res/android">
<group android:checkableBehavior="single">
<item android:id="@+id/nav_call"
android:title="Call"
android:icon="@mipmap/admin"/>
<item android:id="@+id/nav_friends"
android:title="Friends"
android:icon="@mipmap/friends"/>
<item android:id="@+id/nav_location"
android:title="Location"
android:icon="@mipmap/location_surf"/>
<item android:id="@+id/nav_mail"
android:title="Mail"
android:icon="@mipmap/mail"/>
<item android:id="@+id/nav_settings"
android:title="Settings"
android:icon="@mipmap/interfacesettingline"/>
group>
menu>
< group>表示一个组,checkableBehavior指定为single表示组中所有的菜单项只能单选
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="180dp"
android:padding="10dp"
android:background="?attr/colorPrimary">
<de.hdodenhof.circleimageview.CircleImageView
android:layout_width="70dp"
android:layout_height="70dp"
android:id="@+id/icon_image"
android:layout_centerInParent="true"
android:src="@mipmap/szb"/>
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:id="@+id/mail"
android:layout_alignParentBottom="true"
android:text="[email protected]"
android:textColor="#fff"
android:textSize="14sp"/>
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:id="@+id/username"
android:layout_above="@id/mail"
android:text="宋泽斌"
android:textColor="#fff"
android:textSize="14sp"/>
RelativeLayout>
最后,开始使用NacigationView
<androidx.drawerlayout.widget.DrawerLayout 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="match_parent"
android:id="@+id/drawer_layout">
<androidx.coordinatorlayout.widget.CoordinatorLayout
android:layout_width="match_parent"
android:layout_height="match_parent">
<androidx.appcompat.widget.Toolbar
android:layout_width="match_parent"
android:layout_height="?attr/actionBarSize"
android:id="@+id/toolbar2"
android:background="?attr/colorPrimary"
android:theme="@style/ThemeOverlay.AppCompat.Dark.ActionBar"
app:popupTheme="@style/ThemeOverlay.AppCompat.Light">
androidx.appcompat.widget.Toolbar>
androidx.coordinatorlayout.widget.CoordinatorLayout>
<com.google.android.material.navigation.NavigationView
android:layout_width="match_parent"
android:layout_height="match_parent"
android:id="@+id/nav_view"
android:layout_gravity="start"
app:menu="@menu/nav_menu"
app:headerLayout="@layout/nav_header"/>
androidx.drawerlayout.widget.DrawerLayout>
通过app:menu 和 app:headerLayout将我们刚才准备好的menu和headerlayout设置进去,然后在activity中处理点击事件
NavigationView navigationView = findViewById(R.id.nav_view);
navigationView.setCheckedItem(R.id.nav_call);
navigationView.setNavigationItemSelectedListener(new NavigationView.OnNavigationItemSelectedListener() {
@Override
public boolean onNavigationItemSelected(@NonNull MenuItem menuItem) {
drawerLayout.closeDrawers();
return true;
}
});
这里我们只为第一个菜单选项设置了点击事件
<androidx.drawerlayout.widget.DrawerLayout 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="match_parent"
android:id="@+id/drawer_layout">
<androidx.coordinatorlayout.widget.CoordinatorLayout
android:layout_width="match_parent"
android:layout_height="match_parent">
<androidx.appcompat.widget.Toolbar
android:layout_width="match_parent"
android:layout_height="?attr/actionBarSize"
android:id="@+id/toolbar2"
android:background="?attr/colorPrimary"
android:theme="@style/ThemeOverlay.AppCompat.Dark.ActionBar"
app:popupTheme="@style/ThemeOverlay.AppCompat.Light">
androidx.appcompat.widget.Toolbar>
<com.google.android.material.floatingactionbutton.FloatingActionButton
android:id="@+id/fab"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="bottom|end"
android:layout_margin="16dp"
android:src="@mipmap/floatingaction" />
androidx.coordinatorlayout.widget.CoordinatorLayout>
<com.google.android.material.navigation.NavigationView
android:layout_width="match_parent"
android:layout_height="match_parent"
android:id="@+id/nav_view"
android:layout_gravity="start"
app:menu="@menu/nav_menu"
app:headerLayout="@layout/nav_header"/>
androidx.drawerlayout.widget.DrawerLayout>
与上次使用DrawerLayout有不同的是,我们这次在第一个子控件使用CoordinatorLayout布局,这个布局可以监听其所有子控件的各种事件,然后自动为我们做出最为合理的响应,所以在之后弹出Snackerbar的时候,FloatingActionButton才不会被遮挡,而是会向上移动。
点击事件处理
FloatingActionButton fab = findViewById(R.id.fab);
fab.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
}
});
FloatingActionButton fab = findViewById(R.id.fab);
fab.setOnClickListener(this);
public void onClick(View v){
Snackbar.make(v,"Data deleted",Snackbar.LENGTH_SHORT)
.setAction("Undo", new View.OnClickListener() {
@Override
public void onClick(View view) {
Toast.makeText(Second.this, "Data restored", Toast.LENGTH_SHORT).show();
}
}).show();
}
我们为上面的floatingactionbutton设置的点击事件,会产生一个Snackerbar,用make()方法来创建一个Snackerbar对象,make方法第一个参数传入一个view第二个参数就是Snackerbar显示的内容,接着又调用了setAction方法来设置一个动作。