在项目中,很多页面拥有类似的标题,我们只需要改变一些文字和样式就可以做到重用,所以一般的情况都是 :
这样是的确是一种简化开发的方法;但你可能会遇到一下问题:
画标题是项目开发中最简单的时,但同时也很繁琐,作为一个喜欢偷懒的程序员,为何不试着去改变呢!
我的思路:
talking is cheap show me the code
**1.定义基类BaseActivity**
布局文件
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@color/white">
<FrameLayout
android:id="@+id/fl_base_top"
android:layout_width="match_parent"
android:layout_height="48dp">
FrameLayout>
<FrameLayout
android:id="@+id/fl_base_content"
android:layout_width="match_parent"
android:background="@color/white"
android:layout_height="0dp"
android:layout_weight="1">
FrameLayout>
LinearLayout>
基类代码
public abstract class BaseActivity extends AppCompatActivity {
private FrameLayout flBaseTop;//头布局
private FrameLayout flBaseContent;//内容布局
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
//去掉系统的TitleBar
this.getWindow().requestFeature(Window.FEATURE_NO_TITLE);
//初始化content的View
initContentView(R.layout.activity_base);
}
/**
* 子类必须实现,返回一个写好了的 topbar,如果不需要标题,实现方法后返回null就行,
* @return
*/
abstract protected View getTopBar();
private void initContentView(@LayoutRes int layoutResID) {
ViewGroup group = (ViewGroup) findViewById(android.R.id.content); //得到窗口的根布局
group.removeAllViews(); //首先先移除在根布局上的组件
LayoutInflater.from(this).inflate(layoutResID, group, true); //group,true的意思表示添加上去
}
/**
* 这句的意思表示将MainActivity的布局又加到parentLinearLayout的content上
*/
@Override
public void setContentView(@LayoutRes int layoutContentID) {
// super.setContentView(layoutResID);//一定不能调用这句话,不然之前做的添加的布局都被覆盖了
flBaseTop = (FrameLayout) findViewById(R.id.fl_base_top);
flBaseContent = (FrameLayout) findViewById(R.id.fl_base_content);
flBaseStatus = (RelativeLayout) findViewById(R.id.fl_base_status);
evBaseStatus = (EmptyView) findViewById(R.id.ev_base_status);
//将子类的内容布局添加到基类的内容布局中
LayoutInflater.from(this).inflate(layoutContentID, flBaseContent, true);
//将子类实现的标题,添加到基类的标题布局当中
if(getTopBar() != null){
flBaseTop.addView(getTopBar());
flBaseTop.setVisibility(View.VISIBLE);
}else {
flBaseTop.setVisibility(View.GONE);
}
}
}
重要的几个方法:
/**
* 子类必须实现,返回一个写好了的 topbar,如果不需要标题,实现方法后返回null就行,
* @return
*/
abstract protected View getTopBar();
这个方法就是子类必须实现,然后就返回一个写好的,配置好了的标题 view
@Override
public void setContentView(@LayoutRes int layoutContentID) {
// super.setContentView(layoutResID);//一定不能调用这句话,不然之前做的添加的布局都被覆盖了
flBaseTop = (FrameLayout) findViewById(R.id.fl_base_top);
flBaseContent = (FrameLayout) findViewById(R.id.fl_base_content);
flBaseStatus = (RelativeLayout) findViewById(R.id.fl_base_status);
evBaseStatus = (EmptyView) findViewById(R.id.ev_base_status);
//将子类的内容布局添加到基类的内容布局中
LayoutInflater.from(this).inflate(layoutContentID, flBaseContent, true);
//将子类实现的标题,添加到基类的标题布局当中
if(getTopBar() != null){
flBaseTop.addView(getTopBar());
flBaseTop.setVisibility(View.VISIBLE);
}else {
flBaseTop.setVisibility(View.GONE);
}
}
重写setContentView方法,将子类的内容和标题添加到基类里面的布局里面去
if(getTopBar() != null){
flBaseTop.addView(getTopBar());
flBaseTop.setVisibility(View.VISIBLE);
}else {
flBaseTop.setVisibility(View.GONE);
}
上面这行就是将主要的步骤,调用上面定义好的abstract方法getTopBar();添加标题布局;
public class MainActivity extends BaseActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
}
@Override
protected View getTopBar() {
return new T_Style_3_Factory.Builder(this)
.setTab1Str("123")
.setTab2Str("456")
.setCallBack(new Style_3_Callback() {
@Override
public void leftClick() {
}
@Override
public void tab1Click() {
}
@Override
public void tab2Click() {
}
})
.build()
.getTitleView();
}
}
从使用方法可以看到,建立一个复杂的标题就是一个方法,几行代码的事,其实主要的功劳是这个factory,
这个工厂类主要运用了工厂模式,build模式,策略模式来实现。
下面如何讲解建立这个工厂类
1.先定义几个接口和抽象类
工厂抽象类:
public abstract class T_Factoryable {
///////////////////////////////////////////////////////////////////////////
// 样式 1 +--------------------------------+
// | < 返回 标题 |
// +--------------------------------+
// +--------------------------------+
// | < 标题 |
// +--------------------------------+
//
// 样式 2 +--------------------------------+
// | < 返回 标题 文字★ |
// +--------------------------------+
// +--------------------------------+
// | < 返回 标题 ★ |
// +--------------------------------+
// +--------------------------------+
// | < 标题 ★ |
// +--------------------------------+
// 样式 3 +--------------------------------+
// | < (tab1 | tab2) |
// +--------------------------------+
//
///////////////////////////////////////////////////////////////////////////
abstract public View getTitleView();
}
定义点击事件的接口(虽然是空的,但是为了扩展新强,才用的)
public interface StyleCallBack {
}
建立具体工程类
public class T_Style_3_Factory extends T_Factoryable{
// 样式 3 +--------------------------------+
// | < (tab1 | tab2) |
// +--------------------------------+
private Context context;
//左边文字
private String leftString="";
//中间标题
private String centerString="";
//右边文字
private String rightString="";
//左边图片资源
private int leftImgRes;
//右边图片资源
private int rightImgRes;
//点击事件的回调
private StyleCallBack styleCallback;
//tab1 文字
private String tab1Str;
//tab2 文字
private String tab2Str;
Style_3_Callback style_3_Callback;
@Override
public View getTitleView() {
RelativeLayout view;
//得到布局
view = (RelativeLayout) LayoutInflater.from(context).inflate(R.layout.topbar_style3, null);
//左边文字
// TextView tv_left= (TextView) view.findViewById(R.id.tv_left2);
//tab 1 文字
final TextView tv_tab1= (TextView) view.findViewById(R.id.tv_tab1);
//tab 2 文字
final TextView tv_tab2= (TextView) view.findViewById(R.id.tv_tab2);
//左边图标 一般情况下不需要动
ImageView img_left1= (ImageView) view.findViewById(R.id.img_left1);
//textView赋值
// tv_left.setText(leftString);
// tv_center.setText(centerString);
// tv_right1.setText(rightString);
//在没赋值的情况下 左边、右边图标不变
if(-1 != leftImgRes){
img_left1.setImageResource(leftImgRes);
}
if(-1 != rightImgRes){
img_left1.setImageResource(rightImgRes);
}
//策略模式
style_3_Callback= (Style_3_Callback) styleCallback;
tv_tab1.setText(tab1Str);
tv_tab2.setText(tab2Str);
//设置点击事件
img_left1.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
if(style_3_Callback != null){
style_3_Callback.leftClick();
}
}
});
tv_tab1.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
if(style_3_Callback != null){
style_3_Callback.tab1Click();
tv_tab1.setSelected(true);//选择充值
tv_tab2.setSelected(false);//不选中充值卡充值
tv_tab1.setTextColor(context.getResources().getColor(R.color.white));
tv_tab2.setTextColor(context.getResources().getColor(R.color.style_3_color));
tv_tab1.setBackground(context.getResources().getDrawable(R.drawable.shape_style3_left));
tv_tab2.setBackground(context.getResources().getDrawable(R.drawable.shape_style3_right));
}
}
});
tv_tab2.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
if(style_3_Callback != null){
style_3_Callback.tab2Click();
tv_tab1.setSelected(false);//选择充值
tv_tab2.setSelected(true);//不选中充值卡充值
tv_tab1.setTextColor(context.getResources().getColor(R.color.style_3_color));
tv_tab2.setTextColor(context.getResources().getColor(R.color.white));
tv_tab1.setBackground(context.getResources().getDrawable(R.drawable.shape_style3_right1));
tv_tab2.setBackground(context.getResources().getDrawable(R.drawable.shape_style3_left1));
}
}
});
return view;
}
/**
* Build 模式,负责ConstantView的构建
* 使类的 构建 与 使用 分离,能让你 暴露出的接口使用起来更加方便清晰
*/
public static class Builder{
//左边文字
private String leftString="";
//右边文字
private String rightString="";
//左边图片资源
private int leftImgRes=-1;
//右边图片资源
private int rightImgRes=-1;
//上下文
private Context context;
//回调
private StyleCallBack styleCallBack;
//tab1 文字
private String tab1Str;
//tab2 文字
private String tab2Str;
private Builder(){}
public Builder(Context context){
this.context=context;
}
public Builder setLeftString(String leftString){
this.leftString=leftString;
return this;
}
public Builder setRightString(String rightString){
this.rightString=rightString;
return this;
}
public Builder setLeftImgRes(int leftImgRes){
this.leftImgRes=leftImgRes;
return this;
}
public Builder setRightImgRes(int rightImgRes){
this.rightImgRes=rightImgRes;
return this;
}
public Builder setCallBack(StyleCallBack styleCallBack){
this.styleCallBack=styleCallBack;
return this;
}
public Builder setTab1Str(String tab1Str){
this.tab1Str=tab1Str;
return this;
}
public Builder setTab2Str(String tab2Str){
this.tab2Str=tab2Str;
return this;
}
/**
* 完成 build
* @return
*/
public T_Style_3_Factory build(){
T_Style_3_Factory titleFactory=new T_Style_3_Factory();
apply(titleFactory);
return titleFactory;
}
/**
* 将build中的值赋值到 constantView类中
* @param titleFactory
*/
private void apply(T_Style_3_Factory titleFactory){
titleFactory.leftString=this.leftString;
titleFactory.rightString=this.rightString;
titleFactory.leftImgRes=this.leftImgRes;
titleFactory.rightImgRes=this.rightImgRes;
//防止内存泄漏
titleFactory.context=this.context.getApplicationContext();
titleFactory.styleCallback=this.styleCallBack;
titleFactory.tab1Str=this.tab1Str;
titleFactory.tab2Str=this.tab2Str;
}
}
建立标题的具体点击事件接口
public interface Style_3_Callback extends StyleCallBack {
void leftClick();
void tab1Click();
void tab2Click();
}
工厂类的具体职责就是生产配置好的标题view,关于标题的配置其实是一个比较复杂的过程,这里用Builder类来辅助标题的建立,将构建与使用分离;
样式定义好后,将点击事件通过style_3_Callback接口,将点击事件传递出去,
//设置点击事件
img_left1.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
if(style_3_Callback != null){
style_3_Callback.leftClick();
}
}
});
于是使用起来就相当简洁易用
就像这样
@Override
protected View getTopBar() {
return new T_Style_3_Factory.Builder(this)
.setTab1Str("123")
.setTab2Str("456")
.setCallBack(new Style_3_Callback() {
@Override
public void leftClick() {
}
@Override
public void tab1Click() {
}
@Override
public void tab2Click() {
}
})
.build()
.getTitleView();
}
项目以上传github欢迎下载和指教项目地址