BaseActivity 和 ToolBar 的完美结合
2017-03-10 15:59
330 查看
在项目中,很多页面拥有类似的标题,我们只需要改变一些文字和样式就可以做到重用,所以一般的情况都是 :
写一个标题的布局,然后每个页面都去使用“ include ”
自定义view,然后写到你的activity的布局文件里面去使用这个控件。
这样是的确是一种简化开发的方法;但你可能会遇到一下问题:
每写一个页面,你就需要改变布局文件,然后在activity里面找到布局或定义控件,然后给标题设置,或者写点击事件,步骤繁琐;
当某些页面样式改动,你原先写的布局或自定义控件的扩展性不够强,则无法满足需求,然后你必须重新画标题;
画标题是项目开发中最简单的时,但同时也很繁琐,作为一个喜欢偷懒的程序员,为何不试着去改变呢!
我的思路:
在基类BaseActivity中留出一部分布局作为标题布局A,一部分作为内容布局B,将子类的布局全部内容放到基类的内容布局B中(子类的画布局的时候完全不用管标题的部分,后面会有讲到),基类定义abstract方法让子类必须返回一个标题布局,然后将返回的标题布局放到A里面;
建立标题view工厂类,存储各种不同的标题样式,在开发中,根据不同的需求,传入type值,工厂类生产不同的标题出来,然后提供给activity,activity再将这个view提供给基类,放到上面说的标题布局A中;
通过接口回调处理标题的点击事件;
talking is cheap show me the code
基类代码
重要的几个方法:
这个方法就是子类必须实现,然后就返回一个写好的,配置好了的标题 view
重写setContentView方法,将子类的内容和标题添加到基类里面的布局里面去
上面这行就是将主要的步骤,调用上面定义好的abstract方法getTopBar();添加标题布局;
从使用方法可以看到,建立一个复杂的标题就是一个方法,几行代码的事,其实主要的功劳是这个factory,
这个工厂类主要运用了工厂模式,build模式,策略模式来实现。
下面如何讲解建立这个工厂类
1.先定义几个接口和抽象类
工厂抽象类:
定义点击事件的接口(虽然是空的,但是为了扩展新强,才用的)
建立具体工程类
建立标题的具体点击事件接口
工厂类的具体职责就是生产配置好的标题view,关于标题的配置其实是一个比较复杂的过程,这里用Builder类来辅助标题的建立,将构建与使用分离;
样式定义好后,将点击事件通过style_3_Callback接口,将点击事件传递出去,
于是使用起来就相当简洁易用
就像这样
项目以上传github欢迎下载和指教项目地址
写一个标题的布局,然后每个页面都去使用“ include ”
自定义view,然后写到你的activity的布局文件里面去使用这个控件。
这样是的确是一种简化开发的方法;但你可能会遇到一下问题:
每写一个页面,你就需要改变布局文件,然后在activity里面找到布局或定义控件,然后给标题设置,或者写点击事件,步骤繁琐;
当某些页面样式改动,你原先写的布局或自定义控件的扩展性不够强,则无法满足需求,然后你必须重新画标题;
画标题是项目开发中最简单的时,但同时也很繁琐,作为一个喜欢偷懒的程序员,为何不试着去改变呢!
我的思路:
在基类BaseActivity中留出一部分布局作为标题布局A,一部分作为内容布局B,将子类的布局全部内容放到基类的内容布局B中(子类的画布局的时候完全不用管标题的部分,后面会有讲到),基类定义abstract方法让子类必须返回一个标题布局,然后将返回的标题布局放到A里面;
建立标题view工厂类,存储各种不同的标题样式,在开发中,根据不同的需求,传入type值,工厂类生产不同的标题出来,然后提供给activity,activity再将这个view提供给基类,放到上面说的标题布局A中;
通过接口回调处理标题的点击事件;
talking is cheap show me the code
具体实现步骤
**1.定义基类BaseActivity** 布局文件
<?xml version="1.0" encoding="utf-8"?> <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();添加标题布局;
子类继承基类BaseActivity
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欢迎下载和指教项目地址
相关文章推荐
- TableLayout与ToolBar的完美结合?
- 赞叹:Aptana和jquery完美结合,让脚本编写不再难
- Android照片墙完整版,完美结合LruCache和DiskLruCache
- vim与ctags/cscope的完美结合
- Junit和javadoc的完美结合
- Windows 2003系统安全+IIS下Web与FTP的完美结合(下)
- Maven 与 IntelliJ IDEA 的完美结合
- 纯ASP结合VML生成完美图-饼图
- grivdview 模板之dropdownlist完美结合
- Android4.4沉浸状态栏结合CoordinatorLayout,AppBarLayout,CollapsingToolbarLayout等使用详解
- Fckeditor完美结合Struts2(2)――文件上传与重命名
- android--toolbar和侧滑结合的简单实现
- 从Windows到Linux迁移之文件服务器(Samba和AD完美结合)
- boost.asio源码剖析(五) ---- 泛型与面向对象的完美结合
- 现已上线 | 信托与区块链的完美结合:万云助力万向信托重塑商业模式
- POJ 3693 Maximum repetition substring 后缀数组与区间最值的完美结合
- EPPlus与Excel完美的结合
- 2007软件开发2.0大会课程之一:ASP.NET AJAX 与 Silverlight 的完美结合
- office tab 9.2和office2013完美结合
- BaseActivity结合toolbar的简单使用和封装