常用控件和布局的继承结构,如下图:

(待续。。。。)

所有的控件都是直接或间接继承自View的,所用的所有布局都是直接或间接继承自ViewGroup的,View是Android中最基本的一种UI组件,它可以在屏幕上绘制一块矩形区域,并能响应这块区域的各种事件,ViewGroup是一中特殊的View,它可以包含很多的子View和子ViewGroup,是一个用于放置控件和布局的容器。

我们可以利用上面的继承结构来创建自定义控件,创建自定义控件的两种简单方法如下所示。

我们先创建一个UICustomViews项目。

1、引入布局

Android系统已经给每个活动提供了标题栏功能,但我们决定先不使用它,而是创建一个自定义的标题栏。

只需要两个Button和一个TextView,然后在布局中摆好就可以了,但是一般我们的程序中可能有很多个活动都需要这样的标题栏,如果在每个活动的布局中都编写一遍同样的标题栏代码,明显的就会导致代码的大量重复,这个时候,我们可以引入布局的方式来解决这个问题。我们在layout目录下新建一个布局文件title.xml,代码如下:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"android:layout_width="match_parent"android:layout_height="wrap_content"><Buttonandroid:id="@+id/title_back"android:layout_width="wrap_content"android:layout_height="wrap_content"android:layout_gravity="center"android:layout_margin="5dp"android:background="#000"android:text="Back"android:textColor="#f00"/><TextViewandroid:id="@+id/title_text"android:layout_width="0dp"android:layout_height="wrap_content"android:layout_gravity="center"android:layout_weight="1"android:gravity="center"android:background="#000"android:text="Title Text"android:textColor="#f5f"android:textSize="24sp"/><Buttonandroid:id="@+id/title_edit"android:layout_width="wrap_content"android:layout_height="wrap_content"android:layout_gravity="center"android:layout_margin="5dp"android:background="#000"android:text="Edit"android:textColor="#f00"/>
</LinearLayout>

我们在LinearLayout中分别加入了两个Batton和一个TextView,左边的Button可用于返回,右边的Button可用于编辑,中间的TextView则可以用来显示一段标题文本。熟悉一下属性,其中android:backgroud用于为布局或控件指定一个背景,可以使用颜色或者是照片来进行填充。

另外在两个Button中我们都使用了android:layout_margin这个属性,它可以指定控件在上下左右方向上偏移的距离,当然也可以使用android:layout_marginLeft或者android:layout_marginTop等属性来单独指定控件在某个方向上偏移的距离。

那么标题栏文件title.xml我们已经编写完成,那我们如何在程序中使用这个标题栏呢,修改acticity_main.xml中的代码,如下:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"xmlns:app="http://schemas.android.com/apk/res-auto"xmlns:tools="http://schemas.android.com/tools"android:layout_width="match_parent"android:layout_height="match_parent"tools:context="com.example.uicustomviews.MainActivity"> <include layout="@layout/title"/></LinearLayout>

我们只需要通过一行include语句将标题栏布局引进来就可以了。

但是最后,不要忘了在MainActivity中将系统自带的标题栏隐藏掉,代码如下:

package com.example.uicustomviews;import android.support.v7.app.ActionBar;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;public class MainActivity extends AppCompatActivity {@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main); ActionBar actionBar = getSupportActionBar();if(actionBar != null){actionBar.hide();}}
}

我们调用了getSupportActionBar()方法来获得ActionBar的实例,然后再调用ActionBar的hide()方法将标题栏隐藏起来。

使用这种方式,不管有多少布局需要标题栏,只需要一行include语句就可以了。

测试用例如下:

2、创建自定义组件

引入布局的技巧确实解决了重复编写布局代码的问题,但是如果布局中有一些控件要求能够响应事件,我们还是需要在每个活动中为这些控件单独编写一次事件注册的代码。比如说,标题栏的返回按钮,不管在哪一个活动中,都是用来销毁当前活动。为了不增加重复代码,我们使用自定义控件的方式来解决。

新建TitleLayout继承自LinearLayout,让它成为我们自定义的标题栏控件,代码如下:

package com.example.uicustomviews;import android.content.Context;
import android.support.v7.app.ActionBar;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.util.AttributeSet;
import android.view.LayoutInflater;
import android.widget.LinearLayout;public class MainActivity extends AppCompatActivity {@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);ActionBar actionBar = getSupportActionBar();if(actionBar != null){actionBar.hide();}}public class TitleLayout  extends  LinearLayout {public TitleLayout(Context context, AttributeSet attrs) {super(context, attrs);LayoutInflater.from(context).inflate(R.layout.title, this);}}
}

我们重写了LinearLayout中带有两个参数的构造函数,在布局文件中引入TitleLayout控件就会调用这个构造函数,然后在构造函数中需要对标题进行动态加载,这就是要LayoutInflator来实现了。通过LayoutInflator的from()方法可以构建出一个LayoutInflater对象,然后调用inflator()方法就可以动态加载一个布局文件,inflate()接收两个参数,第一个参数是要加载的布局文件的id,我们传入的是R.layout.title,第二个参数是给加载好的布局再添加一个父布局,我们指定为TitleLayout,于是直接传入this。

现在自定义控件已经建好,3、我们还需要在布局文件中添加这个自定义控件,修改activity_main.xml中的代码,如下:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"android:layout_width="match_parent"android:layout_height="match_parent" ><com.example.uicustomviews.TitleLayoutandroid:layout_width="match_parent"android:layout_height="wrap_content" /></LinearLayout>

重新运行程序!

为标题栏的按钮注册点击事件,修改TitleLayout中的代码,如下:

package com.example.uicustomviews;import android.app.Activity;
import android.content.Context;
import android.util.AttributeSet;
import android.view.LayoutInflater;
import android.view.View;
import android.widget.Button;
import android.widget.LinearLayout;
import android.widget.Toast;public class TitleLayout extends LinearLayout {public TitleLayout(Context context, AttributeSet attrs) {super(context, attrs);LayoutInflater.from(context).inflate(R.layout.title, this); Button titleBack = (Button) findViewById(R.id.title_back);Button titleEdit = (Button) findViewById(R.id.title_edit);titleBack.setOnClickListener(new OnClickListener() {@Overridepublic void onClick(View v) {((Activity) getContext()).finish();}});titleEdit.setOnClickListener(new OnClickListener() {@Overridepublic void onClick(View v) {Toast.makeText(getContext(), "You clicked Edit button",Toast.LENGTH_SHORT).show();}});}}

首先通过findViewById()方法得到按钮的实例,然后分别调用setOnClickListener()方法给两个按钮注册了点击事件,当点击返回按钮时,销毁当前的活动,当点击编辑按钮时弹出一段文本。

效果如下图:

Android 第八课 创建自定义控件相关推荐

  1. Android开发系列之创建自定义控件

    Android开发过程中我们经常需要定义自己的控件,一方面基于复用的角度考虑,一方面也是基于逻辑处理思维的角度考虑.在这篇博客里面,笔者想要介绍.总结几种Android自定义控件的方法,如果有什么不对 ...

  2. Android群英传笔记——第三章:Android控件架构与自定义控件讲解

    Android群英传笔记--第三章:Android控件架构与自定义控件讲解 真的很久没有更新博客了,三四天了吧,搬家干嘛的,心累,事件又很紧,抽时间把第三章大致的看完了,当然,我还是有一点View的基 ...

  3. NeHe OpenGL第二十八课:贝塞尔曲面

    NeHe OpenGL第二十八课:贝塞尔曲面 贝塞尔曲面: 这是一课关于数学运算的,没有别的内容了.来,有信心就看看它吧. 贝塞尔曲面 作者: David Nikdel ( ogapo@ithink. ...

  4. 斯坦福大学机器学习第八课“神经网络的表示(Neural Networks: Representation)”

    斯坦福大学机器学习第八课"神经网络的表示(Neural Networks: Representation)" 斯坦福大学机器学习第八课"神经网络的表示(Neural Ne ...

  5. Android 图形架构 之三—— 创建Layer、Surface、SurfaceControl

    前言 上一篇我们分析了,app与SurfaceFlinger建立连接的过程,现在我们就可以继续往下分析,看下创建Surface的过程. 我们可以将Surface理解为一个绘图表面,Android应用程 ...

  6. 第八课 k8s源码学习和二次开发原理篇-KubeBuilder使用和Controller-runtime原理

    第八课 k8s源码学习和二次开发原理篇-KubeBuilder使用和Controller-runtime原理 tags: k8s 源码学习 categories: 源码学习 二次开发 文章目录 第八课 ...

  7. 【C++探索之旅】第一部分第八课:传值引用,文件源头

    内容简介 1.第一部分第八课:传值引用,文件源头 2.第一部分第九课预告:数组威武,动静合一 传值引用,文件源头 这一课的标题有点怪.其实是由这一课的几个重点内容结合起来取的名,慢慢学习就知道啦. 上 ...

  8. Linux 探索之旅 | 第五部分第八课:用 Shell 做统计练习

    -- 作者 谢恩铭 转载请注明出处 <Linux探索之旅>全系列 内容简介 前言 成果展示 解题步骤和答案 可能的优化 第五部分第九课预告 1. 前言 上一课 Linux探索之旅 | 第五 ...

  9. 第八课 k8s网络基础学习-VxLAN基础

    第八课 k8s网络基础学习-VxLAN基础 tags: k8s网络 eNSP wireshark VxLAN 文章目录 第八课 k8s网络基础学习-VxLAN基础 第一节 VxLAN 1.1 VxLA ...

最新文章

  1. 为什么要把html改为jsp,为什么要用ZHTML替换JSP
  2. Java课堂测试——一维数组
  3. 第四章 SQL*plus介绍、常用命令
  4. 成功解决ValueError: Unable to add relationship because child variable ‘ID‘ in ‘cats_df‘ is also its inde
  5. python 导入包 作用域_Python 包、模块、函数、变量作用域
  6. git 码云 使用记录
  7. leetcode题解56-合并区间
  8. mysql i o error_警告:mysqli_ERROR()需要精确的一个参数,0给定的错误
  9. (C语言)猴子选大王
  10. 现代 C++ 救不了程序员!
  11. indesign教程,了解基本文本格式
  12. NHibernate配置 使用经验
  13. 电化学稳态阻抗谱(EIS)在等效电路已知的情况下进行拟合,python第三方工具包impedance.py
  14. 小程序 房租水电费记录管理_一点通房租物业收据打印软件下载
  15. 【日常篇】006_从黑体辐射到RGB——如何定量计算光谱的颜色?
  16. DM8安装及使用DTS工具将oracle11g迁移到centos7.6上的DM8
  17. 国产游戏面临新一轮洗牌?虚幻4引擎免费开源
  18. 博客系统程序(页面设计)
  19. 网页dom元素过多为什么会导致页面卡顿
  20. php转存百度云盘,[转]Linux定时备份数据到百度云盘

热门文章

  1. linux 如何查看终端格式,你应该还不知道,Linux终端下的 Markdown 文档查看器
  2. 捕捉所有异常_详解Java中异常的分类
  3. Hash冲突的解决--暴雪的Hash算法
  4. 洛谷P1073 Tarjan + 拓扑排序 // 构造分层图
  5. git常用配置(指令)
  6. A*算法在最短路问题的应用及其使用举例
  7. Restful对于URL的简化
  8. 2017-05-12-Linux文件操作
  9. 详解-制作根文件系统,并使用yaffs,jffs,nfs挂载系统(2)
  10. Python---时间函数