Andriod 自定义控件之创建可以复用的组合控件
前面已学习了一种自定义控件的实现,是Andriod 自定义控件之音频条,还没学习的同学可以学习下,学习了的同学也要去温习下,一定要自己完全的掌握了,再继续学习,贪多嚼不烂可不是好的学习方法,我们争取学习了一种技术就会一种技术,而且不光看了就算了,最好的方法就是看完我自己再练习下,再扩展下,在原来的基础上在添加一些东西,比如,增加一些功能实现等等。
今天我们打算学习下另外一种自定义控件,就是创建可重复使用的组合控件,那么问题来了:
- 什么是可重复使用?
就是在应用中,可以在多个地方共同使用一套代码。这样不仅能减少我们的工作量,而且还能保持应用风格的一致,这种应用最多最直接的体现就是统一风格样式的标题栏。 - 那什么又是组合控件呢?
组合控件,顾名思义就是多个控件组合在一起,相互协作共同完成某些特定的功能。
下面我们就针对app应用中风格统一的标题栏来开始我们的学习。
首先,既然是一组组合的控件,那就必须有一个可以来包含这些控件的容器,我们所接触的可以存放控件的容器很多,比如LinearLayout、RelativeLayout等等多种Layout,今天我们就选择RelativeLayout来做我们的容器。和以前一样,我们先定义一个CompositeViews类来继承RelativeLayout类,并重写它的构造方法,代码如下:
public class CompositeViews extends RelativeLayout{
public CompositeViews(Context context) {
this(context,null);
}
public CompositeViews(Context context, AttributeSet attrs) {
this(context, attrs,0);
}
public CompositeViews(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
}
}
接下来,我们再定义三个TextView控件,分别是mLefeText,mRightText,textTitle用来显示“返回”,“搜索”以及“标题”并且使用LayoutParams规定它们在容器里面的对齐方式。请看代码:
public class CompositeViews extends RelativeLayout{
private TextView mLefeText;
private TextView mRightText;
private TextView textTitle;
private LayoutParams leftLayoutParams;
private LayoutParams ridhtLayoutParams;
private LayoutParams titleLayoutParams;
public CompositeViews(Context context) {
this(context,null);
}
public CompositeViews(Context context, AttributeSet attrs) {
this(context, attrs,0);
}
public CompositeViews(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
initView(context);
}
initView(context)方法中是用来初始化三个组合控件的,请看:
private void initView(Context context) {
mLefeText = new TextView(context);
mRightText = new TextView(context);
textTitle = new TextView(context);
/*
* 左按钮位置
*/
leftLayoutParams = new LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT);
leftLayoutParams.addRule(RelativeLayout.ALIGN_PARENT_LEFT,TRUE);
mLefeText.setText("返回");
mLefeText.setTextSize(22);
/*
* 右按钮位置
*/
ridhtLayoutParams = new LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT);
ridhtLayoutParams.addRule(RelativeLayout.ALIGN_PARENT_RIGHT,TRUE);
mRightText.setText("搜索");
mRightText.setTextSize(22);
/*
* 中间标题位置
*/
titleLayoutParams = new LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT);
titleLayoutParams.addRule(RelativeLayout.CENTER_IN_PARENT,TRUE);
textTitle.setText("这是一个标题");
textTitle.setTextSize(22);
}
ok,以上的代码已经实现了组合控件的显示和对齐方式,我们把定义的View添加到布局文件中并在Activity加载吧
activity_main.xml文件
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:custom="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:background="#999999"
android:layout_height="wrap_content"
android:orientation="vertical">
<com.sanhuimusic.mycustomview.view.CompositeViews
android:id="@+id/topBar"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
/>
</LinearLayout>
MainActivity:
public class MainActivity extends AppCompatActivity{
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
}
}
我们先来运行看下结果
ok,已显示出来了,但是相信大家也看出来了,这上面的代码中,各个控件中的属性是都是我们固定写死的,既然我们是创建可服用的控件,固定写死的东西肯定是不可取的,那么我们怎么可以灵活地获取控件的属性,以至于能达到复用呢?
这就必须要接触另外一种技术了,就是自定义属性。用我们自定义的属于可以在每次使用我们定义的控件时为其分配属性即可。下面我们来学习下自定义属性。
自定义属性其实也是相当的简单,首先,我们现在资源文件res下values目录下新建一个attrs.xml文件(eclipse自带,as自建),新建的attrs.xml是一个包含如下代码的文件:
<?xml version="1.0" encoding="utf-8"?>
<resources>
</resources>
在resources中有各种属性供我们使用,同学们可以自己看下。根据我们现在的需求,我们选择使用declare-styleable来声明我们的属性集,然后为其定义特有的name属性,这个name是供我们在使用自定义属性时,通过它可以查找到里面的所有属性。请看如下代码:
<?xml version="1.0" encoding="utf-8"?>
<resources>
<declare-styleable name="CompositeViews">
<attr name="titleText" format="string"/>
<attr name="titleTextSize" format="dimension"/>
<attr name="titleColor" format="color"/>
<attr name="titleBackground" format="color|reference"/>
<attr name="leftTextColor" format="color"/>
<attr name="leftBackground" format="color|reference"/>
<attr name="leftText" format="string"/>
<attr name="leftTextSize" format="dimension"/>
<attr name="rightTextColor" format="color"/>
<attr name="rightBackground" format="color|reference"/>
<attr name="rightText" format="string"/>
<attr name="rightTextSize" format="dimension"/>
</declare-styleable>
</resources>
单独拿一行属性来解析下它所代表的含义:如 :attr代表的是一个属性,它里面所包含name字段是这条属性名,通过该属性名可以获取以format的约束为真的属性值;formate是该属性的格式,分别包含string,dimension,color,reference等等,分别代表字符串,大小,颜色,引用。其他的大家可以自行学习resources所包含的属性。
好了,自定义属性我们已学习完毕,那么该怎么使用我们自己定义的属性呢?其实也很简单,在我们的activity_main.xml文件中直接使用我们定义的属性就可以了,但是在使用是之前必须在指定引用第三方控件的命名空间,在跟布局文件中添加如下一行代码:
xmlns:custom="http://schemas.android.com/apk/res-auto"
custom是我们第三方命名空间的名字,可以任意命名,我们在使用自定义属性时必须以它开头。请看代码:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:custom="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:background="#999999"
android:layout_height="wrap_content"
android:orientation="vertical">
<com.sanhuimusic.mycustomview.view.CompositeViews
android:id="@+id/topBar"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
custom:titleText="@string/titleText"
custom:titleColor="#000000"
custom:titleTextSize="@dimen/titleTextSize"
custom:titleBackground="#999999"
custom:leftText="@string/leftText"
custom:leftTextColor="#FFFFFF"
custom:leftBackground="#666666"
custom:leftTextSize="@dimen/leftTextSize"
custom:rightText="@string/rightText"
custom:rightTextColor="#FFFFFF"
custom:rightBackground="#666666"
custom:rightTextSize="@dimen/rightTextSize"
/>
</LinearLayout>
我们是使用custom加上我们自定义属性里面< attr name="titleText" format="string"/>里的name值来动态设置属性值的,如:custom:titleText="@string/titleText"。
ok,在我们xml文件中已设定好属性值,那么该怎么显示出来呢?这个是需要通过一个类型组TypedArray来获取的,它里面包含各种从AttributeSet属性集中获取属性的方法,所以我们修改上面的构造方法和initView(context)方法,如下所示:
private void initView(Context context, AttributeSet attrs) {
mLefeText = new TextView(context);
mRightText = new TextView(context);
textTitle = new TextView(context);
/**
* 获取自定义属性
*/
TypedArray typedArray = context.obtainStyledAttributes(attrs, R.styleable.CompositeViews);
String titleText = typedArray.getString(R.styleable.CompositeViews_titleText);
float titleTextSize = typedArray.getDimension(R.styleable.CompositeViews_titleTextSize, 16);
int titleColor = typedArray.getColor(R.styleable.CompositeViews_titleColor,0);
Drawable titleBackground = typedArray.getDrawable(R.styleable.CompositeViews_titleBackground);
String leftText = typedArray.getString(R.styleable.CompositeViews_leftText);
int leftTextColor = typedArray.getColor(R.styleable.CompositeViews_leftTextColor, 0);
float leftTextSize = typedArray.getDimension(R.styleable.CompositeViews_leftTextSize, 16);
Drawable leftBackground = typedArray.getDrawable(R.styleable.CompositeViews_leftBackground);
String rightText = typedArray.getString(R.styleable.CompositeViews_rightText);
int rightTextColor = typedArray.getColor(R.styleable.CompositeViews_rightTextColor, 0);
float rightTextSize = typedArray.getDimension(R.styleable.CompositeViews_rightTextSize, 16);
Drawable rightBackground = typedArray.getDrawable(R.styleable.CompositeViews_rightBackground);
typedArray.recycle();
/*
* 左按钮位置
*/
leftLayoutParams = new LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT);
leftLayoutParams.addRule(RelativeLayout.ALIGN_PARENT_LEFT,TRUE);
mLefeText.setText(leftText);
mLefeText.setTextColor(leftTextColor);
mLefeText.setTextSize(leftTextSize);
mLefeText.setBackground(leftBackground);
addView(this.mLefeText,leftLayoutParams);
/*
* 右按钮位置
*/
ridhtLayoutParams = new LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT);
ridhtLayoutParams.addRule(RelativeLayout.ALIGN_PARENT_RIGHT,TRUE);
mRightText.setText(rightText);
mRightText.setTextColor(rightTextColor);
mRightText.setTextSize(rightTextSize);
mRightText.setBackground(rightBackground);
addView(mRightText,ridhtLayoutParams);
/*
* 中间标题位置
*/
titleLayoutParams = new LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT);
titleLayoutParams.addRule(RelativeLayout.CENTER_IN_PARENT,TRUE);
textTitle.setText(titleText);
textTitle.setTextSize(titleTextSize);
textTitle.setTextColor(titleColor);
textTitle.setBackground(titleBackground);
addView(textTitle,titleLayoutParams);
}
代码解释:首先通过上下文context获取到属性存放到TypedArray 中,然后通过TypedArray 里封装好的各种方法获取对应的属性值,然后再分别为我们的控件设置属性。这样就完成了,自定义属性的使用,并且复用度高,每当需要使用标题栏是都只需要在xml中添加我们定义的View控件,为其配置属性即可使用,节约了开发时间,提高了效率,并且还保持的app风格的一致。
好,到这里感觉已经讲完了整个过程吧,其实还有一个重要的实现还没有讲。我们的控件已经可以呈现出来了,但是怎么完成里面控件的作用呢?
这里比较常见的做法是利用回调机制来实现功能的开发,首先我们先定义一个接口,创建两个方法,用于左右控件的点击事件。
public interface TopBarClickListener{
void leftClickListener();
void rightClickListener();
}
然后在构造方法中为左右控件添加点击事件,但不实现功能,等待调用者自己实现:
private void setListener() {
mLefeText.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
mTopBarClickListener.leftClickListener();
}
});
mRightText.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
mTopBarClickListener.rightClickListener();
}
});
}
再者,把定义好的接口暴露给调用者:
public void setOnTopBarClickListener(TopBarClickListener topBarClickListener){
mTopBarClickListener = topBarClickListener;
}
最后,谁调用,谁实现。这就完成了不同界面复用控件实现不同的功能的便利。在这里我们只在MainActivity中打印Toast就可以了。
public class MainActivity extends AppCompatActivity {
private CompositeViews topBar;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
topBar = (CompositeViews) findViewById(R.id.topBar);
topBar.setOnTopBarClickListener(new CompositeViews.TopBarClickListener(){
@Override
public void leftClickListener() {
ToastUtil.makeText(MainActivity.this,"您点击了返回键",Toast.LENGTH_SHORT).show();
}
@Override
public void rightClickListener() {
ToastUtil.makeText(MainActivity.this,"您点击了搜索键",Toast.LENGTH_SHORT).show();
}
});
}
}
OK,看看结果吧
好,已经可以实现我们的需求了,是不是学会很多呢。
今天主要讲了android自定义View中另一种的实现,并且还学习了自定义属性,同学们下去好好消化下,并自己动手现实一两个例子吧,好了,今天就讲到这里,谢谢大家。
更多资讯请关注微信平台,有博客更新会及时通知。爱学习爱技术。
Andriod 自定义控件之创建可以复用的组合控件的更多相关文章
- ASP.NET自定义控件组件开发 第四章 组合控件开发CompositeControl
原文:ASP.NET自定义控件组件开发 第四章 组合控件开发CompositeControl 第四章 组合控件开发CompositeControl 大家好,今天我们来实现一个自定义的控件,之前我们已经 ...
- ASP.NET自定义控件组件开发 第四章 组合控件开发CompositeControl 后篇 --事件冒泡
原文:ASP.NET自定义控件组件开发 第四章 组合控件开发CompositeControl 后篇 --事件冒泡 CompositeControl 后篇 --事件冒泡 系列文章链接: ASP.NET ...
- ASP.NET自定义控件组件开发 第五章 模板控件开发
原文:ASP.NET自定义控件组件开发 第五章 模板控件开发 第五章 模板控件开发 系列文章链接: ASP.NET自定义控件组件开发 第一章 待续 ASP.NET自定义控件组件开发 第一章 第二篇 接 ...
- ASP.NET自定义控件组件开发 第三章 为控件添加事件 前篇
原文:ASP.NET自定义控件组件开发 第三章 为控件添加事件 前篇 第三章 为控件添加事件 好了,我们之前以前开发一个控件.而且也添加了属性,开发也很规范,但是那个控件还差最后一点:添加事件. 系列 ...
- ASP.NET自定义控件组件开发 第三章 为控件添加事件 后篇
原文:ASP.NET自定义控件组件开发 第三章 为控件添加事件 后篇 第三章 为控件添加事件 后篇 前一篇文章只是简单的说了下事件,但是大家应该方法,在ASP.NET自定义控件中只是简单那么定义事件是 ...
- Android自定义控件之自定义组合控件
前言: 前两篇介绍了自定义控件的基础原理Android自定义控件之基本原理(一).自定义属性Android自定义控件之自定义属性(二).今天重点介绍一下如何通过自定义组合控件来提高布局的复用,降低开发 ...
- Android自定义控件之自定义组合控件(三)
前言: 前两篇介绍了自定义控件的基础原理Android自定义控件之基本原理(一).自定义属性Android自定义控件之自定义属性(二).今天重点介绍一下如何通过自定义组合控件来提高布局的复用,降低开发 ...
- 自定义控件之--组合控件(titlebar)
自定义控件相关知识从郭霖等大神身上学习,这里只不过加上自己的理解和实践,绝非抄袭. 组合控件是自定义控件中最简单的方式,但是是入门自定义控件和进阶的过程: 那么常见的组合控件有那些? 比如titl ...
- Android开发技巧——自定义控件之组合控件
Android开发技巧--自定义控件之组合控件 我准备在接下来一段时间,写一系列有关Android自定义控件的博客,包括如何进行各种自定义,并分享一下我所知道的其中的技巧,注意点等. 还是那句老话,尽 ...
随机推荐
- 面向组合子设计Coder
面向组合子 面向组合子(Combanitor-Oriented),是最近帮我打开新世界大门的一种pattern.缘起haskell,又见monad与ParseC,终于ajoo前辈的几篇文章. 自去年9 ...
- .NET基础拾遗(2)面向对象的实现和异常的处理基础
Index : (1)类型语法.内存管理和垃圾回收基础 (2)面向对象的实现和异常的处理基础 (3)字符串.集合与流 (4)委托.事件.反射与特性 (5)多线程开发基础 (6)ADO.NET与数据库开 ...
- C#对WebApi数据操作
目标 简化并统一程序获取WebApi对应实体数据的过程,方便对实体进行扩充.原理就是数据服务使用反射发现数据提供者,处理好泛型就行. 相关传送门:Restful WebApi开发实践 先来看下最后的请 ...
- Tomcat 8熵池阻塞变慢详解(putty)
原因 Tomcat 7/8都使用org.apache.catalina.util.SessionIdGeneratorBase.createSecureRandom类产生安全随机类SecureRand ...
- php使用CI发送qq和163邮件
1.需求 发送邮件 2.介绍 使用CI框架的email类库发送邮件,这里演示QQ和163 3.163使用教程 a.先去163邮件开启smtp邮件. b.在CI的控制器里写下面的代码 $this-> ...
- springmvc 配置01
springmvc请求流程与struts比较 1.添加包 com.springsource.org.aopalliance-1.0.0.jarcom.springsource.org.apache ...
- Javascript的“上下文”(context)
一:JavaScript中的“上下文“指的是什么 百科中这样定义: 上下文是从英文context翻译过来,指的是一种环境. 在软件工程中,上下文是一种属性的有序序列,它们为驻留在环境内的对象定义环境. ...
- 关于for循环中,定义的i的作用域的问题。
for(var i=0;i<2;i++){ console.log(i) } console.log(i) 经过测试:在IE9+,谷歌,火狐中.都出现了0,1,2三个值. 所以其作用域在整个上下 ...
- cookies如何成为全局变量以及设置,删除,获取
(一)cookie机制将信息存储于用户硬盘,因此可以作为全局变量 (1)保存用户登录状态.例如将用户id存储于一个cookie内,这样当用户下次访问该页面时就不需要重新登录了,现在很多论坛和社区都提供 ...
- SQL Server-数据类型(七)
前言 前面几篇文章我们讲解了索引有关知识,这一节我们再继续我们下面内容讲解,简短的内容,深入的理解,Always to review the basics. 数据类型 SQL Server支持两种字符 ...