Android自定义控件之自定义组合控件

时间:2022-12-17 17:39:16

前言:

前两篇介绍了自定义控件的基础原理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标签

Android自定义控件之自定义组合控件

使用merge标签

Android自定义控件之自定义组合控件

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>

显示效果

Android自定义控件之自定义组合控件

总结:

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

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

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

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

  2. android自定义控件&lpar;五&rpar; 自定义组合控件

    转自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. &lbrack;android&rsqb; 手机卫士自定义组合控件

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

  6. Android自定义组合控件详细示例 &lpar;附完整源码&rpar;

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

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

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

  8. Android中自定义组合控件

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

  9. 014 Android 自定义组合控件

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

随机推荐

  1. cout 格式化输出

    一直习惯于C语言的printf函数来打印,突然有一天要用cout来打印,发现有点不适应. 原来cout也是有格式化输出的. 首先要引入头文件 #include<iostream> // 在 ...

  2. 关于oracle中数据类型的选择

    由于是初学,犯了如下错误: 生成表的主键id时,用当前时间的毫秒值.而在oracle中定义主键id时,用的数据类型是char(32).在mybatis中通过id取数据怎么也取不出来.想了好几天,本来以 ...

  3. SQL Server join介绍

    介绍Inner Join(可以省略Inner,平常经常inner,就是inner join), Full Out Join,Cross Join,Left Join, Right Join区别. )) ...

  4. WebRTC 音视频开发之路

    早在2014年就通过WebRTC实现了PC客户端的实时视频语音,那时P2P连接的建立使用的WebRTC自带的libjingle库,使用peerconnection的API实现的.后来在做远程桌面,文件 ...

  5. matrix67:kmp算法详解

    个人认为KMP是最没有必要讲的东西,因为这个东西网上能找到很多资料.但网上的讲法基本上都涉及到“移动(shift)”.“Next函数”等概念,这非常容易产生误解(至少一年半前我看这些资料学习KMP时就 ...

  6. EasyUI - Datatable转Json and Json转Datatable

    using System; using System.Data; using System.Linq; using System.Collections; using System.Collectio ...

  7. 507&period; Perfect Number

    We define the Perfect Number is a positive integer that is equal to the sum of all its positive divi ...

  8. &lbrack;django&rsqb; 利用多线程增加异步任务

    看到django异步大家的反应应该是celery这种消息队列组件,现在用的最多的最推荐的也是这种方式.然而我这需求就是请求来了,执行一个小程序,但是又不能确定这个小程序啥时候执行完,响应又要及时,丢给 ...

  9. QML学习笔记(四)-TabView-竖直方向

    源码:https://github.com/sueRimn/QML-ExampleDemos 作者: 狐狸家的鱼 Github: 八至 版权声明:如需转载请获取授权和联系作者 想实现垂直竖直方向的Ta ...

  10. supervisord&period;conf

    ; Sample supervisor config file.;; For more information on the config file, please see:; http://supe ...