TopBar
开发过程中我们经常需要在Activity中使用自定义TopBar,如果每个Activity都在xml添加的TopBar组件,然后再在Activity中设置标题什么的,无疑是非常繁琐的,这个时候封装一个常用的BaseTopBarActivity是非常必要的。
效果及说明
如图最左边,通常的一个按钮(返回键),一个标题栏,最右边一个菜单。
菜单栏无需封装,直接在所需的Activity使用Menu就可以。所以直接封装按钮和标题栏即可。
简单封装
修改Style
使用Theme.AppCompat.Light.NoActionBar去掉原有的ActionBar
<resources>
//使用Theme.AppCompat.Light.NoActionBar去掉原有的ActionBar
<style name="AppTheme" parent="Theme.AppCompat.Light.NoActionBar">
<item name="colorPrimary">@color/colorPrimary</item>
<item name="colorPrimaryDark">@color/colorPrimaryDark</item>
<item name="colorAccent">@color/colorAccent</item>
</style>
</resources>
使用,几行代码而已
public class MainActivity extends BaseTopBarActivity {
@Override
protected int getContentView() {
return R.layout.activity_main;
}
@Override
protected void init(Bundle savedInstanceState) {
setTitle("hello");//修改标题
}
//通过getMenuInflater()方法得到MenuInflater对象
public boolean onCreateOptionsMenu(Menu menu) {
getMenuInflater().inflate(R.menu.main, menu);
//如果返回false,创建的菜单无法显示
return true;
}
public boolean onOptionsItemSelected(MenuItem item) {
//通过调用item.getItemId()来判断菜单项
switch (item.getItemId()) {
case R.id.add_item:
Toast.makeText(this, "You Clicked Add", Toast.LENGTH_SHORT).show();
break;
case R.id.remove_item:
Toast.makeText(this, "You clicked Remove", Toast.LENGTH_SHORT).show();
break;
default:
}
return true;
}
}
除去Menu组件所用到的代码,思想上面返回键+标题栏,只需要重写两个方法:
1. getContentView():用来return获取当前Activity的布局文件。
2. init(Bundle savedInstanceState):因为继承的关系,用来代替onCreate(Bundle savedInstanceState),后面详细说明。
封装BaseTopBarActivity
XML
布局很简单,一个ToolpBar和一个FrameLayout就行了,所有的操作都在ToolBar上进行。
<?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"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
tools:context="com.demon.demontest.BaseTopBarActivity">
<android.support.v7.widget.Toolbar
android:id="@+id/toolbar"
android:layout_width="match_parent"
android:layout_height="50dp"
android:background="@color/colorPrimary"
android:fitsSystemWindows="true"
app:navigationIcon="?attr/homeAsUpIndicator"
app:popupTheme="@style/ThemeOverlay.AppCompat.Light"></android.support.v7.widget.Toolbar>
<FrameLayout
android:id="@+id/viewContent"
android:layout_width="match_parent"
android:layout_height="match_parent"></FrameLayout>
</LinearLayout>
FrameLayout的作用:
我们封装的思想是写一个BaseTopBarActivity继承AppCompatActivity或者Activity,然后让需要用TopBar的Activity继承BaseTopBarActivity,此处以MainActvity为例。所以BaseTopBarActivity的内容就是一个TopBar+MainActvity。而FrameLayout就是用来转载MainActvity的布局。
BaseTopBarActivity
public abstract class BaseTopBarActivity extends AppCompatActivity {
@BindView(R.id.toolbar)
Toolbar toolbar;
@BindView(R.id.viewContent)
FrameLayout viewContent;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_base_top_bar);
ButterKnife.bind(this);
//初始化设置ToolBar,必须放在toolbar调用的方法之前
setSupportActionBar(toolbar);
getSupportActionBar().setDisplayShowTitleEnabled(false);
//按钮事件,可以用Toolbar的方法修改按钮Icon,也可以跟设置标题一样写在方法里,重写按钮事件
toolbar.setNavigationOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
finish();//此处返回
}
});
//将继承 TopBarBaseActivity 的布局解析到 FrameLayout里面
LayoutInflater.from(this).inflate(getContentView(), viewContent);
init(savedInstanceState);
}
//设置标题
protected void setTitle(String text) {
toolbar.setTitle(text);
toolbar.setTitleTextColor(getResources().getColor(R.color.white));
}
//获取继承的布局
protected abstract int getContentView();
//代替onCreate初始化,防止重复加载
protected abstract void init(Bundle savedInstanceState);
}
核心思想:
- 使用抽象类的方法,使BaseTopBarActivity可以被继承。
- 然后使用抽象方法,使得可以重写,从而修改标题,如果按钮事件需要改变,也可以跟修改标题一样进行重写。
- 代码注释写点很详细,就不再多讲。
总结
到这里我们的 TopBarBaseActivity 就封装完了,过程比较简单,重要的是这个封装的思路,其实还有很多我们常用的布局都是可以进行封装的。