前言:

前两篇介绍了自定义控件的基础原理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. 干货分享:让你分分钟学会 JS 闭包

    闭包,是 Javascript 比较重要的一个概念,对于初学者来讲,闭包是一个特别抽象的概念,特别是ECMA规范给的定义,如果没有实战经验,很难从定义去理解它.因此,本文不会对闭包的概念进行大篇幅描述 ...

  2. MVC Core 网站开发(Ninesky) 2.1、栏目的前台显示

    上次创建了栏目模型,这次主要做栏目的前台显示.涉及到数据存储层.业务逻辑层和Web层.用到了迁移,更新数据库和注入的一些内容. 一.添加数据存储层 1.添加Ninesky.DataLibrary(与上 ...

  3. TypeScript Vs2013 下提示Can not compile modules unless '--module' flag is provided

    VS在开发TypeScript程序时候,如果import了模块有的时候会有如下提示: 这种情况下,只需要对当前TypeScript项目生成设置为AMD规范即可!

  4. 玩转spring boot——结合AngularJs和JDBC

    参考官方例子:http://spring.io/guides/gs/relational-data-access/ 一.项目准备 在建立mysql数据库后新建表“t_order” ; -- ----- ...

  5. 一行代码实现java list去重

    1.不带类型写法: 1 List listWithoutDup = new ArrayList(new HashSet(listWithDup)); 2.带类型写法(以String类型为例):1)Ja ...

  6. pandas基础-Python3

    未完 for examples: example 1: # Code based on Python 3.x # _*_ coding: utf-8 _*_ # __Author: "LEM ...

  7. ReactiveCocoa代码实践之-UI组件的RAC信号操作

    上一节是自己对网络层的一些重构,本节是自己一些代码小实践做出的一些demo程序,基本涵盖大多数UI控件操作. 一.用UISlider实现调色板 假设我们现在做一个demo,上面有一个View用来展示颜 ...

  8. 如何理解MySQL中auto_increment?

    1.auto_increment用于主键自动增长.比如从1开始增长,当把第一条数据删除,再插入第二条数据时,主键值为2,不是1.

  9. Mysql - 查询之关联查询

    查询这块是重中之重, 关系到系统反应时间. 项目做到后期, 都是要做性能测试和性能优化的, 优化的时候, 数据库这块是一个大头. sql格式: select 列名/* from 表名 where 条件 ...

  10. Ubuntu 16.04 安装 arm-linux-gcc 嵌入式交叉编译环境 问题汇总

    闲扯: 实习了将近半年一直在做硬件以及底层的驱动,最近要找工作了发现了对linux普遍要求很高,而且工作岗位也非常多,所以最近一些时间在时不时地接触linux. 正文:(我一时兴起开始写博客,准备不充 ...