前言:

前两篇介绍了自定义控件的基础原理Android自定义控件之基本原理(一)、自定义属性Android自定义控件之自定义属性(二)。今天重点介绍一下如何通过自定义组合控件来提高布局的复用,降低开发成本,以及维护成本。

自定义控件相关文章地址:

使用自定义组合控件的好处?

我们在项目开发中经常会遇见很多相似或者相同的布局,比如APP的标题栏,我们从三种方式实现标题栏来对比自定义组件带来的好处,毕竟好的东西还是以提高开发效率,降低开发成本为导向的。

1.)第一种方式:直接在每个xml布局中写相同的标题栏布局代码

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:lee="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"> <RelativeLayout
android:layout_width="match_parent"
android:background="@color/green"
android:layout_height="45dp"> <Button
android:id="@+id/title_bar_left"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentLeft="true"
android:layout_centerVertical="true"
android:layout_marginLeft="5dp"
android:background="@mipmap/titlebar_back_icon"
android:minHeight="45dp"
android:minWidth="45dp"
android:textSize="14sp" /> <TextView
android:id="@+id/title_bar_title"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerInParent="true"
android:text="登录"
android:singleLine="true"
android:textSize="17sp" /> <Button
android:id="@+id/title_bar_right"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentRight="true"
android:layout_centerVertical="true"
android:layout_marginRight="7dp"
android:text="提交"
android:textColor="@android:color/white"
android:background="@null"
android:minHeight="45dp"
android:minWidth="45dp"
android:textSize="14sp" />
</RelativeLayout> </LinearLayout>

这种方式没有任何布局复用的概念,同时也让当前的布局变得臃肿难以维护,开发效率低下,而且这个还需要要求每个开发人员必须细心否则有可能会做出参差不齐的标题栏,所以这种方式是最不推荐使用的。

2.)第二种方式:使用include标签

首先定义标题栏布局

    <RelativeLayout
android:layout_width="match_parent"
android:background="@color/green"
android:layout_height="45dp"> <Button
android:id="@+id/title_bar_left"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentLeft="true"
android:layout_centerVertical="true"
android:layout_marginLeft="5dp"
android:minHeight="45dp"
android:minWidth="45dp"
android:textSize="14sp" /> <TextView
android:id="@+id/title_bar_title"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerInParent="true"
android:singleLine="true"
android:textSize="17sp" /> <Button
android:id="@+id/title_bar_right"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentRight="true"
android:layout_centerVertical="true"
android:layout_marginRight="7dp"
android:background="@null"
android:minHeight="45dp"
android:minWidth="45dp"
android:textSize="14sp" />
</RelativeLayout>

然后在需要的地方通过include标签实现引用

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:lee="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"> <include layout="@layout/view_title_bar" /> </LinearLayout>

通过上面的布局代码,我们可以使用上面这种方式确实实现了布局的复用,而且也避免了开发人员开发出参差不齐标题栏的问题,但是同时也引入了新的问题,比如更加降低了开发效率,加大了开发成本,问题就在我们该如何为每个布局文件定义标题栏?只有通过代码的方式来设置标题问题,左右按钮等其他的属性,导致布局属性和Activity代码耦合性比较高,所以这种方式也不是推荐的方式。

3.)第三种方式:通过自定义组合控件

这里先不具体介绍如何实现一个自定义组合控件,这里先介绍一下自定义组合控件带来的好处。

  • 提高布局文件开发效率
  • 降低布局文件维护成本
  • 降低布局文件和Activity代码耦合性
  • 容易扩展
  • 简单易用

如何实现一个自定义组合控件

1.)先定义一个布局文件

<merge xmlns:android="http://schemas.android.com/apk/res/android">

    <Button
android:id="@+id/title_bar_left"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentLeft="true"
android:layout_centerVertical="true"
android:layout_marginLeft="5dp"
android:background="@null"
android:minHeight="45dp"
android:minWidth="45dp"
android:textSize="14sp" /> <TextView
android:id="@+id/title_bar_title"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerInParent="true"
android:singleLine="true"
android:textSize="17sp" /> <Button
android:id="@+id/title_bar_right"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentRight="true"
android:layout_centerVertical="true"
android:layout_marginRight="7dp"
android:background="@null"
android:minHeight="45dp"
android:minWidth="45dp"
android:textSize="14sp" /> </merge>

注意:这里为何要使用merge标签,自定义组合控件时会继承RelativeLayout、LinearLayout等控件,这样导致布局的层级无形中增加了一层,如下是对比:

未使用merge标签

使用merge标签

2.)定义自定义属性

比如标题文字、标题栏左边按钮图标等。

 <declare-styleable name="CustomTitleBar">
<attr name="title_background_color" format="reference|integer" />
<attr name="left_button_visible" format="boolean" />
<attr name="right_button_visible" format="boolean" />
<attr name="title_text" format="string" />
<attr name="title_text_color" format="color" />
<attr name="title_text_drawable" format="reference|integer" />
<attr name="right_button_text" format="string" />
<attr name="right_button_text_color" format="color" />
<attr name="right_button_drawable" format="reference|integer" />
<attr name="left_button_text" format="string" />
<attr name="left_button_text_color" format="color" />
<attr name="left_button_drawable" format="reference|integer" />
</declare-styleable>

3.)自定义一个View根据需求继承不同的ViewGroup子类,比如:RelativeLayout、LinearLayout等,我们这里继承RelativeLayout。

public class CustomTitleBar extends RelativeLayout {
private Button titleBarLeftBtn;
private Button titleBarRightBtn;
private TextView titleBarTitle; public CustomTitleBar(Context context, AttributeSet attrs) {
super(context, attrs);
LayoutInflater.from(context).inflate(R.layout.custom_title_bar, this, true);
titleBarLeftBtn = (Button) findViewById(R.id.title_bar_left);
titleBarRightBtn = (Button) findViewById(R.id.title_bar_right);
titleBarTitle = (TextView) findViewById(R.id.title_bar_title); TypedArray attributes = context.obtainStyledAttributes(attrs, R.styleable.CustomTitleBar);
if (attributes != null) {
//处理titleBar背景色
int titleBarBackGround = attributes.getResourceId(R.styleable.CustomTitleBar_tlb_title_background_color, Color.GREEN);
setBackgroundResource(titleBarBackGround);
//先处理左边按钮
//获取是否要显示左边按钮
boolean leftButtonVisible = attributes.getBoolean(R.styleable.CustomTitleBar_tlb_left_button_visible, true);
if (leftButtonVisible) {
titleBarLeftBtn.setVisibility(View.VISIBLE);
} else {
titleBarLeftBtn.setVisibility(View.INVISIBLE);
}
//设置左边按钮的文字
String leftButtonText = attributes.getString(R.styleable.CustomTitleBar_tlb_left_button_text);
if (!TextUtils.isEmpty(leftButtonText)) {
titleBarLeftBtn.setText(leftButtonText);
//设置左边按钮文字颜色
int leftButtonTextColor = attributes.getColor(R.styleable.CustomTitleBar_tlb_left_button_text_color, Color.WHITE);
titleBarLeftBtn.setTextColor(leftButtonTextColor);
}
//设置左边图片icon 这里是二选一 要么只能是文字 要么只能是图片
int leftButtonDrawable = attributes.getResourceId(R.styleable.CustomTitleBar_tlb_left_button_drawable, R.mipmap.titlebar_back_icon);
if (leftButtonDrawable != -1) {
titleBarLeftBtn.setCompoundDrawablesWithIntrinsicBounds(leftButtonDrawable, 0, 0, 0); //设置到哪个控件的位置()
} //处理标题
//先获取标题是否要显示图片icon
int titleTextDrawable = attributes.getResourceId(R.styleable.CustomTitleBar_tlb_title_text_drawable, -1);
if (titleTextDrawable != -1) {
titleBarTitle.setBackgroundResource(titleTextDrawable);
} else {
//如果不是图片标题 则获取文字标题
String titleText = attributes.getString(R.styleable.CustomTitleBar_tlb_title_text);
if (!TextUtils.isEmpty(titleText)) {
titleBarTitle.setText(titleText);
}
//获取标题显示颜色
int titleTextColor = attributes.getColor(R.styleable.CustomTitleBar_tlb_title_text_color, Color.WHITE);
titleBarTitle.setTextColor(titleTextColor);
} //先处理右边按钮
//获取是否要显示右边按钮
boolean rightButtonVisible = attributes.getBoolean(R.styleable.CustomTitleBar_tlb_right_button_visible, true);
if (rightButtonVisible) {
titleBarRightBtn.setVisibility(View.VISIBLE);
} else {
titleBarRightBtn.setVisibility(View.INVISIBLE);
}
//设置右边按钮的文字
String rightButtonText = attributes.getString(R.styleable.CustomTitleBar_tlb_right_button_text);
if (!TextUtils.isEmpty(rightButtonText)) {
titleBarRightBtn.setText(rightButtonText);
//设置右边按钮文字颜色
int rightButtonTextColor = attributes.getColor(R.styleable.CustomTitleBar_tlb_right_button_text_color, Color.WHITE);
titleBarRightBtn.setTextColor(rightButtonTextColor);
}
//设置右边图片icon 这里是二选一 要么只能是文字 要么只能是图片
int rightButtonDrawable = attributes.getResourceId(R.styleable.CustomTitleBar_tlb_right_button_drawable, -1);
if (rightButtonDrawable != -1) {
titleBarRightBtn.setCompoundDrawablesWithIntrinsicBounds(0, 0, rightButtonDrawable, 0); //设置到哪个控件的位置()
}
attributes.recycle();
}
} public void setTitleClickListener(OnClickListener onClickListener) {
if (onClickListener != null) {
titleBarLeftBtn.setOnClickListener(onClickListener);
titleBarRightBtn.setOnClickListener(onClickListener);
}
} public Button getTitleBarLeftBtn() {
return titleBarLeftBtn;
} public Button getTitleBarRightBtn() {
return titleBarRightBtn;
} public TextView getTitleBarTitle() {
return titleBarTitle;
} }

4.)在不同的XML布局中引用

关于如何使用自定义属性这里就不再说明了,为了更加直观的查看效果,我这里在一个布局文件中实现不同要求的标题栏

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:lee="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"> <com.whoislcj.views.CustomTitleBar
android:layout_width="match_parent"
android:layout_height="45dp"
android:layout_marginTop="10dp"
lee:right_button_drawable="@mipmap/titlebar_add_icon"
lee:title_background_color="@color/green"
lee:title_text="标题1" /> <com.whoislcj.views.CustomTitleBar
android:layout_width="match_parent"
android:layout_height="45dp"
android:layout_marginTop="10dp"
lee:right_button_visible="false"
lee:title_background_color="@color/green"
lee:title_text="标题2" /> <com.whoislcj.views.CustomTitleBar
android:layout_width="match_parent"
android:layout_height="45dp"
android:layout_marginTop="10dp"
lee:left_button_text="左边"
lee:right_button_text="右边"
lee:title_background_color="@color/red"
lee:title_text="标题3" /> <com.whoislcj.views.CustomTitleBar
android:layout_width="match_parent"
android:layout_height="45dp"
android:layout_marginTop="10dp"
lee:left_button_text="左边"
lee:right_button_drawable="@mipmap/titlebar_add_icon"
lee:title_background_color="@color/red"
lee:title_text="标题4" /> <com.whoislcj.views.CustomTitleBar
android:layout_width="match_parent"
android:layout_height="45dp"
android:layout_marginTop="10dp"
lee:left_button_text="左边"
lee:left_button_text_color="@color/red"
lee:right_button_drawable="@mipmap/titlebar_add_icon"
lee:title_background_color="@color/blue"
lee:title_text="标题5" /> <com.whoislcj.views.CustomTitleBar
android:layout_width="match_parent"
android:layout_height="45dp"
android:layout_marginTop="10dp"
lee:left_button_text="左边"
lee:left_button_text_color="@color/red"
lee:right_button_drawable="@mipmap/titlebar_add_icon"
lee:title_background_color="@color/blue"
lee:title_text="标题6"
lee:title_text_color="@color/black" /> </LinearLayout>

显示效果

总结:

通过本篇文章我们得知,通过自定义组合控件确实能够提高开发效率,降低维护成本,但是也需要UI设计风格保持高度一致,不然的话只能呵呵哒了!所以想要做好一个app需要一个有共识的团队才行。本篇介绍到此为止,下一篇要更新什么我还没有想好!有可能是自定义控件的事件回调,也有可能自定义ViewGroup实现流式布局。

Android自定义控件之自定义组合控件的更多相关文章

  1. Android自定义控件之自定义组合控件(三)

    前言: 前两篇介绍了自定义控件的基础原理Android自定义控件之基本原理(一).自定义属性Android自定义控件之自定义属性(二).今天重点介绍一下如何通过自定义组合控件来提高布局的复用,降低开发 ...

  2. android自定义控件(五) 自定义组合控件

    转自http://www.cnblogs.com/hdjjun/archive/2011/10/12/2209467.html 代码为自己编写 目标:实现textview和ImageButton组合, ...

  3. Android 手机卫士--自定义组合控件构件布局结构

    由于设置中心条目中的布局都很类似,所以可以考虑使用自定义组合控件来简化实现 本文地址:http://www.cnblogs.com/wuyudong/p/5909043.html,转载请注明源地址. ...

  4. Android开发之自定义组合控件

    自定义组合控件的步骤1.自定义一个View,继承ViewGroup,比如RelativeLayout2.编写组合控件的布局文件,在自定义的view中加载(使用View.inflate())3.自定义属 ...

  5. [android] 手机卫士自定义组合控件

    设置中心 新建SettingActivity 设置GridView条目的点击事件 调用GridView对象的setOnItemClickListenner()方法,参数:OnItemClickList ...

  6. Android自定义组合控件详细示例 (附完整源码)

    在我们平时的Android开发中,有时候原生的控件无法满足我们的需求,或者经常用到几个控件组合在一起来使用.这个时候,我们就可以根据自己的需求创建自定义的控件了,一般通过继承View或其子类来实现. ...

  7. Android开发学习笔记-自定义组合控件的过程

    自定义组合控件的过程 1.自定义一个View 一般来说,继承相对布局,或者线性布局 ViewGroup:2.实现父类的构造方法.一般来说,需要在构造方法里初始化自定义的布局文件:3.根据一些需要或者需 ...

  8. Android中自定义组合控件

    Android中自定义控件的情况非常多,一般自定义控件可以分为两种:继承控件及组合控件.前者是通过继承View或其子类,重写方法实现自定义的显示及事件处理方式:后者是通过组合已有的控件,来实现结构的简 ...

  9. 014 Android 自定义组合控件

    1.需求介绍 将已经编写好的布局文件,抽取到一个类中去做管理,下次还需要使用类似布局时,直接使用该组合控件的对象. 优点:可复用. 例如要重复利用以下布局: <RelativeLayout an ...

随机推荐

  1. RPC 使用中的一些注意点

    最近线上碰到一点小问题,分析其原因发现是出在对 RPC 使用上的一些细节掌握不够清晰导致.很多时候我们做业务开发会把 RPC 当作黑盒机制来使用,但若不对黑盒的工作原理有个基本掌握,也容易犯一些误用的 ...

  2. SQLServer事务同步下如何收缩日志

    事务同步是SQLServer做读写分离的一种常用的方式. 随着业务数据的不断增长,数据库积攒了大量的日志,为了腾出硬盘空间,需要对数据库日志进行清理 订阅数据库的日志清理 因为订阅数据库所有的数据都来 ...

  3. 在.Net中实现自己的简易AOP

    RealProxy基本代理类 RealProxy类提供代理的基本功能.这个类中有一个GetTransparentProxy方法,此方法返回当前代理实例的透明代理.这是我们AOP实现的主要依赖. 新建一 ...

  4. 【翻译】Awesome R资源大全中文版来了,全球最火的R工具包一网打尽,超过300+工具,还在等什么?

    0.前言 虽然很早就知道R被微软收购,也很早知道R在统计分析处理方面很强大,开始一直没有行动过...直到 直到12月初在微软技术大会,看到我软的工程师演示R的使用,我就震惊了,然后最近在网上到处了解和 ...

  5. CRL快速开发框架系列教程十(导出对象结构)

    本系列目录 CRL快速开发框架系列教程一(Code First数据表不需再关心) CRL快速开发框架系列教程二(基于Lambda表达式查询) CRL快速开发框架系列教程三(更新数据) CRL快速开发框 ...

  6. JQuery easyUI DataGrid 创建复杂列表头(译)

    » Create column groups in DataGrid The easyui DataGrid has ability to group columns, as the followin ...

  7. seaJs学习笔记2 – seaJs组建库的使用

    原文地址:seaJs学习笔记2 – seaJs组建库的使用 我觉得学习新东西并不是会使用它就够了的,会使用仅仅代表你看懂了,理解了,二不代表你深入了,彻悟了它的精髓. 所以不断的学习将是源源不断. 最 ...

  8. gulp批量打包文件并提取公共文件

    gulp是前端开发过程中对代码进行构建的工具,是自动化项目的构建利器. browseriyf是模块化打包工具. 一般情况下,Browserify 会把所有的模块打包成单个文件.单个文件在大多数情况下是 ...

  9. css实现文本框和下拉框结合的案例

    html 代码部分 <div id="list-name-input" class="list-name-input"> <select ty ...

  10. 如何搭建git服务器

    一.前言 现在越来越多的公司用git进行版本控制,不过git是默认是开源的,如果私有的话是需要付费的,如果不想付费自己可以搭建一个git服务器用来版本控制. 二.服务器端操作 1.安装git sudo ...