在最近的一个项目中,由于有多个活动要用到toolbar,所以一个一个编写的代价比较大。这里的思路是写一个含有toolbar的布局的活动,需要有toolbar的活动继承这个活动,然后将自己的布局文件装入toolbar下面的view。
来看布局文件的部分布局:
<android.support.v7.widget.Toolbar
android:id="@+id/toolbar"
android:layout_width="match_parent"
android:layout_height="?attr/actionBarSize"
android:background="@drawable/backgroundcolor"
android:theme="@style/ThemeOverlay.AppCompat.Dark.ActionBar">
<TextView
android:text="取消"
android:visibility="invisible"
android:id="@+id/tvLeft"
android:textColor="#fff"
android:layout_width="wrap_content"
android:layout_height="wrap_content" />
<TextView
android:id="@+id/title"
android:layout_gravity="center"
style="@style/TextAppearance.AppCompat.Widget.ActionBar.Title"
android:text="cwncnsd"
android:layout_width="wrap_content"
android:layout_height="wrap_content" />
</android.support.v7.widget.Toolbar>
<FrameLayout
android:id="@+id/contentView"
android:layout_width="match_parent"
android:layout_height="match_parent"/>
LayoutInflater.from(ToolBarBaseActivity.this).inflate(getContentView(),contentView);
这样继承带来的问题就是灵活性的牺牲,子活动只能触碰这个framelayout,无法应对一些需求。比如需要侧滑菜单,需要在toolbar上左侧显示文字取消。所以要尽量把这个基类布局设计的完善,主要包括:
1.根布局使用drawerlayout,提供一个内容布局和一个侧滑菜单布局给子活动装入。
2.在toolbar上添加两个文本框,一个作为左侧可能显示的文本按钮(默认不显示),另一个是显示在中间的标题,使用系统定义的style。
这样布局文件就写完了,接下来看活动代码:
1.首先是onCreate:
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_tool_bar_base);
toolbar= (Toolbar) findViewById(R.id.toolbar);
tv= (TextView) findViewById(R.id.title);
tvLeft= (TextView) findViewById(R.id.tvLeft);
setSupportActionBar(toolbar);
getSupportActionBar().setDisplayShowTitleEnabled(false);//原默认标题不显示
//将子活动的布局加载到内容布局中
contentView= (FrameLayout) findViewById(R.id.contentView);
LayoutInflater.from(ToolBarBaseActivity.this).inflate(getContentView(),contentView);
//加载侧滑菜单
sidemenu= (FrameLayout) findViewById(R.id.sidemenu);
LayoutInflater.from(ToolBarBaseActivity.this).inflate(getSideMenu(),sidemenu);
drawer= (DrawerLayout) findViewById(R.id.drawer);
//给出初始化方法,传递缓存数据
init(savedInstanceState);
}
关于toolbar的初始化,禁用原标题,以及把两个布局文件装入内容布局和侧滑菜单,这里使用了两个抽象方法,直接返回布局文件ID,要求子类实现。还有就是定义抽象方法init,并传递onCreate的参数。
2.提供控制侧滑菜单的方法:
protected void openDrawer(){
drawer.openDrawer(GravityCompat.END);
}
protected void closeDrawer(){ drawer.closeDrawer(GravityCompat.END); }
protected void hideDrawer(){
drawer.setDrawerLockMode(DrawerLayout.LOCK_MODE_LOCKED_CLOSED); //关闭手势滑动
}
分别是开启菜单,关闭菜单和禁用菜单。有些活动用不到侧滑菜单,需要在初始化时禁用。
3.设置toolbar上的item:
toolbar的item分成两部分,左侧的navigation和右侧加载的一个item菜单。左侧的比较好设置:
protected void setLeftButton(int buttonId, MyOnClickListener listener){
this.leftlistener=listener;
toolbar.setNavigationIcon(buttonId);
}
监听不能在这里直接设置,所以自定义了一个监听接口并创建实例,在这里把参数传入实例,稍后会设置监听。
前面还提到了不用这个navigation而是用那个文本框,这个就比较简单了:
protected void setLeftButton(String buttonText, View.OnClickListener listener){
tvLeft.setVisibility(View.VISIBLE);
tvLeft.setText(buttonText);
tvLeft.setOnClickListener(listener);
}
protected void setRightButton(int i,String s,MyOnClickListener rightlistener){
this.rightId=i;
this.rightTitle=s;
this.rightlistener=rightlistener;
}
接下来调用API进行真正的右侧图标设置:
先写一个菜单布局文件:
<?xml version="1.0" encoding="utf-8"?>
<menu xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto">
<item android:id="@+id/item1"
android:title=""
app:showAsAction="always"/>
</menu>
很简单,就一个item。
接下来:
@Override
public boolean onCreateOptionsMenu(Menu menu) {
if (rightId!= 0|| !TextUtils.isEmpty(rightTitle)){
getMenuInflater().inflate(R.menu.toolbar_menu,menu);
}
return super.onCreateOptionsMenu(menu);
}
@Override
public boolean onPrepareOptionsMenu(Menu menu) {
if (rightId!=0){
menu.findItem(R.id.item1).setIcon(rightId);
}
if (!TextUtils.isEmpty(rightTitle)){
menu.findItem(R.id.item1).setTitle(rightTitle);
}
return super.onPrepareOptionsMenu(menu);
}
先判断rightId是否有,也就是用户是否设置,然后加载菜单。
设置监听:
@Override
public boolean onOptionsItemSelected(MenuItem item) {
if (item.getItemId()==android.R.id.home){
leftlistener.onClick();
} else {
rightlistener.onClick();
}
return true;//此事件已处理
}
这个方法相当于toolbar的点击回调,左侧按钮的id是android.R.id.home,这个是固定的。点击时调用我们自定义的回调方法就可以了。
这样基本就写完了,其他的可以封装一下显示进度条什么的,
完整代码:
package com.example.a.app10.Activity;
import android.app.ProgressDialog;
import android.support.v4.view.GravityCompat;
import android.support.v4.view.ViewCompat;
import android.support.v4.widget.DrawerLayout;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.support.v7.widget.Toolbar;
import android.text.TextUtils;
import android.view.LayoutInflater;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.view.ViewGroup;
import android.view.Window;
import android.view.WindowManager;
import android.widget.FrameLayout;
import android.widget.TextView;
import android.widget.Toast;
import com.example.a.app10.R;
import com.example.a.app10.tool.Net;
import q.rorbin.badgeview.QBadgeView;
public abstract class ToolBarBaseActivity extends AppCompatActivity {
private Toolbar toolbar;
private MyOnClickListener leftlistener,rightlistener;
private int rightId;
private String rightTitle;
private FrameLayout contentView,sidemenu;
private TextView tv;
private DrawerLayout drawer;
private ProgressDialog mProgressDialog;
private TextView tvLeft;
public interface MyOnClickListener{
void onClick();
}
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_tool_bar_base);
toolbar= (Toolbar) findViewById(R.id.toolbar);
tv= (TextView) findViewById(R.id.title);
tvLeft= (TextView) findViewById(R.id.tvLeft);
setSupportActionBar(toolbar);
getSupportActionBar().setDisplayShowTitleEnabled(false);//原默认标题不显示
//将子活动的布局加载到内容布局中
contentView= (FrameLayout) findViewById(R.id.contentView);
LayoutInflater.from(ToolBarBaseActivity.this).inflate(getContentView(),contentView);
//加载侧滑菜单
sidemenu= (FrameLayout) findViewById(R.id.sidemenu);
LayoutInflater.from(ToolBarBaseActivity.this).inflate(getSideMenu(),sidemenu);
drawer= (DrawerLayout) findViewById(R.id.drawer);
a();
//给出初始化方法,传递缓存数据
init(savedInstanceState);
}
protected abstract int getSideMenu();
protected abstract void init(Bundle savedInstanceState);
protected abstract int getContentView();
@Override
public boolean onOptionsItemSelected(MenuItem item) {
if (item.getItemId()==android.R.id.home){
leftlistener.onClick();
} else {
rightlistener.onClick();
}
return true;//此事件已处理
}
@Override
public boolean onCreateOptionsMenu(Menu menu) {
if (rightId!= 0|| !TextUtils.isEmpty(rightTitle)){
getMenuInflater().inflate(R.menu.toolbar_menu,menu);
}
return super.onCreateOptionsMenu(menu);
}
@Override
public boolean onPrepareOptionsMenu(Menu menu) {
if (rightId!=0){
menu.findItem(R.id.item1).setIcon(rightId);
}
if (!TextUtils.isEmpty(rightTitle)){
menu.findItem(R.id.item1).setTitle(rightTitle);
}
return super.onPrepareOptionsMenu(menu);
}
protected void setLeftButton(int buttonId, MyOnClickListener listener){
this.leftlistener=listener;
toolbar.setNavigationIcon(buttonId);
}
protected void setLeftButton(String buttonText, View.OnClickListener listener){
tvLeft.setVisibility(View.VISIBLE);
tvLeft.setText(buttonText);
tvLeft.setOnClickListener(listener);
}
protected void setRightButton(int i,String s,MyOnClickListener rightlistener){
this.rightId=i;
this.rightTitle=s;
this.rightlistener=rightlistener;
}
protected void setMyTitle(String i){
tv.setText(i);
}
protected void openDrawer(){
drawer.openDrawer(GravityCompat.END);
}
private void a() {
Window window = getWindow();
//设置透明状态栏,这样才能让 ContentView 向上
window.addFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS);
}
//显示进度对话框
protected void showProgress(String msg) {
if (mProgressDialog == null) {
mProgressDialog = new ProgressDialog(this);
mProgressDialog.setCancelable(true);
}
mProgressDialog.setMessage(msg);
mProgressDialog.show();
}
protected void hideProgress() {
if (mProgressDialog != null) {
mProgressDialog.dismiss();
}
}
protected void hideDrawer(){
drawer.setDrawerLockMode(DrawerLayout.LOCK_MODE_LOCKED_CLOSED); //关闭手势滑动
}
protected void closeDrawer(){
drawer.closeDrawer(GravityCompat.END);
}
}