博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
Android开发技巧——自定义控件之组合控件
阅读量:5995 次
发布时间:2019-06-20

本文共 3328 字,大约阅读时间需要 11 分钟。

Android开发技巧——自定义控件之组合控件

我准备在接下来一段时间,写一系列有关Android自定义控件的博客,包括如何进行各种自定义,并分享一下我所知道的其中的技巧,注意点等。

还是那句老话,尽管我知道会被爬虫机器给过滤掉。
本文原创,转载请注明在CSDN博客上的出处:

今天写第一篇,就先写一下最简单的,也就是我们大概最早接触的一类自定义——组合控件。

这里仅讨论使用布局文件来进行组合控件。
为什么不用Java代码来写布局?原因是没有布局文件直观明了,能预览,好维护。

下面来看一个例子。

假如我们在一个界面当中的某部分布局,在另外一个界面中也会用到。
这里写图片描述
例如如上图所示,圈起来的内容,可能除了在支付界面上用到,在记录界面上也会用到,那么,你会如何处理这种情况呢?。我们先把布局实现一下:

接着:

直接复制代码

最新手的做法是,选中,复制,到另一个布局文件粘贴。然后会发现,要改一下界面的时候,要两边跟着改。直到我们学习了<include>标签之后。

使用<include>标签

于是,我们把这部分界面给抽出来,到一个新的布局文件中。然后在两个布局当中都include一下。现在如果要改这部分的界面,我们只需要改抽出来的那个文件即可,如果不涉及到所include的布局本身的属性的话。

现在看来是不是好多了?尽管只看布局代码是这样的,但是——
通常我们都不是写一个界面就这样了事了,我们还要在Java代码上,对一些控件设置一些文字,背景色,或是设置点击事件等等。而这部分的界面相同,它们的UI逻辑通常情况下也是相同的。显然,同样的代码要写两遍,作为一个有着懒惰习惯的程序员来说,当然是极极不情愿的。

自定义组合控件

于是我们定义一个类,继承自ViewGroup的子类,因为我们这里是组合一些控件,这些控件是要放在一个控件的容器里,所以不能是继承自View。我们把这个类命名为 LoginTipView,代码如下:

import android.app.Activity;import android.content.Context;import android.util.AttributeSet;import android.view.Gravity;import android.view.View;import android.widget.RelativeLayout;import android.widget.TextView;/** * 提示去登录注册的View * @author Geek_Soledad * @since 15-5-26 */public class LoginTipView extends RelativeLayout implements View.OnClickListener{
private TextView mLogin; public LoginTipView(Context context, AttributeSet attrs) { super(context, attrs); addView(View.inflate(context, R.layout.view_login_tip, null)); mLogin = (TextView) findViewById(R.id.login_register); mLogin.setOnClickListener(this); } @Override public void onClick(View v) { getContext().startActivity(new Intent(getContext(), LoginActivity.class)); }}

看这一行代码:

addView(View.inflate(context, R.layout.view_login_tip, null));

我们把一个布局,通过View.inflate()方法加载出来,并且通过调用addView方法,把它加到我们的LoginTipView中。

然后在我们其他使用到这部分界面的布局代码中这样引用:

并且由于我们的登录的点击事件写在了LoginTipView里,所以我们甚至不需要在其他的Java代码里来设这个点击事件。

但是上面的代码还是有很大的优化余地的。最主要的是,我们的LoginTipView本身就继承自RelativeLayout,而它里面又放了一个我们从布局文件中加载的RelativeLayout,显然这部分内容可以合并。下面开始优化:

优化

首先,我们把布局代码的根元素改为`标签:

然后LoginTipView代码改为如下:

public class LoginTipView extends RelativeLayout implements View.OnClickListener{
private TextView mLogin; public LoginTipView(Context context, AttributeSet attrs) { super(context, attrs); LayoutInflater.from(context).inflate(R.layout.view_login_tip, this, true); this.setGravity(Gravity.CENTER_VERTICAL); int padding = getResources().getDimensionPixelSize(R.dimen.padding_common); this.setPadding(padding, 0, padding, 0); mLogin = (TextView) findViewById(R.id.login_register); mLogin.setOnClickListener(this); this.setBackgroundResource(R.color.bg_login_tip_view); } @Override public void onClick(View v) { LoginMainActivity.showWithClosable((Activity) getContext()); }}

注意,我们现在加载布局的代码改为了LayoutInflater.from(context).inflate(R.layout.view_login_tip, this, true);,当然,使用View.inflate(context, R.layout.view_login_tip, this);也是一样的,后者在方法里面也是在调用前者的方法。然后,因为我们已经改为<merge>标签了,所以要把公共的属性写到我们的LoginTipView代码里(当然,你也可以不写,那你就需要在引用这个控件的布局代码里设置其对应属性)。

我们的优化过程是,使用<merge>标签,并在inflate时传入一个ViewGroup对象,使布局文件<merge>里的控件直接加载到这个ViewGroup里,减少层级。

对于这种自定义控件,其实可以说是对组合使用的控件的封装。需要注意的是,这时候你在<merge>元素本身定义的布局属性都是无效的。而这些你需要设定的属性,比如上面例子中的背景色,你可以写在你所封装的控件里,也是写在引用它的布局里。

下篇预告:

应该会讲一下onDraw(Canvas)来实现自定义吧。

你可能感兴趣的文章
【leetcode】143. Reorder List
查看>>
java多线程基本概述(二十五)——Exchanger
查看>>
123456
查看>>
[Vue warn]: Cannot find element: #app
查看>>
Core Animation2-CABasicAnimation
查看>>
自定义分页
查看>>
Ubuntu Eclipse配置Python开发环境
查看>>
Smtp协议与Pop3协议的简单实现
查看>>
数独~~~~~~只记得当下的眼疼
查看>>
【菜鸟学习笔记】bootstrap_字体图标
查看>>
P3299 [SDOI2013]保护出题人
查看>>
HTTP状态码
查看>>
charles mock数据时解决乱码问题
查看>>
[TJOI2019]唱、跳、rap和篮球
查看>>
linux服务器网络优化配置
查看>>
Android-使用ViewFlipper实现轮番切换广告栏
查看>>
oo第一单元作业总结
查看>>
angular ng-repeat radio取值
查看>>
HDU 4812 D Tree
查看>>
权限组件(5):权限粒度控制到按钮
查看>>