Android自定义组合控件详细示例 (附完整源码)
在我们平时的Android开发中,有时候原生的控件无法满足我们的需求,或者经常用到几个控件组合在一起来使用.这个时候,我们就可以根据自己的需求创建自定义的控件了,一般通过继承View或其子类来实现.
实现一个自定义控件一般需要下面三个步骤:
1. 设计控件中需要的属性 (xml)
2. 实现自定义的View (java)
3. 引用自定义的View (xml)
下面我们通过实例来实现一个完整的自定义组合控件--TopBar,左右两边各一个Button,中间是一个TextView.
先看下最终效果:

下面通过代码来完成自定义控件的完整过程.
.设计控件中需要的属性
我们可以先把要实现的自定义控件画一个草图,来分析需要设计哪些属性.我们需要在values资源文件夹下创建一个定义控件的xml文件.
atts.xml
<?xml version="1.0" encoding="utf-8"?>
<resources>
<!--
使用declare-styleable标签定义控件,name为控件名
使用attr标签定义控件的属性,name为属性名,format为属性的类型
-->
<declare-styleable name="topBar">
<attr name="tbTitle" format="string" />
<attr name="titleTextSize" format="dimension" />
<attr name="titleTextColor" format="color" /> <attr name="leftText" format="string" />
<attr name="leftBackground" format="reference|color" />
<attr name="leftTextColor" format="color" /> <attr name="rightText" format="string" />
<attr name="rightBackground" format="reference|color" />
<attr name="rightTextColor" format="color" />
</declare-styleable>
</resources>
.实现自定义的View
TopBar.java
package scratchcard.cbt.com.learnuserdefinedview; import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.drawable.Drawable;
import android.util.AttributeSet;
import android.view.Gravity;
import android.view.View;
import android.view.ViewGroup;
import android.widget.Button;
import android.widget.RelativeLayout;
import android.widget.TextView; /**
* Created by caobotao on 15/12/9.
*/
public class TopBar extends RelativeLayout{
/**
* 声明控件
*/
private Button leftBtn;//左按钮
private TextView textView;//中间文本框
private Button rightBtn;//右按钮 /**
* 声明三个控件的属性
*/
//声明左按钮的属性
private String leftText;//按钮文本
private Drawable leftBackground;//按钮背景
private int leftTextColor;//按钮文本颜色
//声明中间文本框的属性
private String tbTitle;//文本框文本
private float titleTextSize;//文本框字体大小
private int titleTextColor;//文本框字体颜色
//声明右按钮的属性
private String rightText;//按钮文本
private Drawable rightBackground;//按钮背景
private int rightTextColor;//按钮文本颜色 /**
* 声明三个控件的布局属性
*/
private LayoutParams leftBtnLayoutParams;
private LayoutParams textViewLayoutParams;
private LayoutParams rightBtnLayoutParams; //声明左右按钮点击监听
private TopBarBtnsOnClickListener listener; //创建一个监听左右按钮点击的接口
public interface TopBarBtnsOnClickListener{
public void leftBtnOnClick();//左按钮被点击的事件
public void rightBtnOnClick();//右按钮被点击的事件
} //向外提供一个设置监听的方法
public void setOnTopBarBtnsClick(TopBarBtnsOnClickListener listener){
this.listener = listener;
} //重写构造方法
public TopBar(Context context, AttributeSet attrs) {
super(context, attrs);
/**
* 用TypedArray可以获取用户在xml中声明的此控件的所有属性,以键值对存储,
* K:资源文件(例 R.styleable.topBar_leftText)
* V:属性值
*/
TypedArray ta = context.obtainStyledAttributes(attrs,R.styleable.topBar); //为左按钮的属性赋值
leftText = ta.getString(R.styleable.topBar_leftText);
leftBackground = ta.getDrawable(R.styleable.topBar_leftBackground);
leftTextColor = ta.getInt(R.styleable.topBar_leftTextColor,0); //为中间的文本框的属性赋值
tbTitle = ta.getString(R.styleable.topBar_tbTitle);
titleTextSize = ta.getDimension(R.styleable.topBar_titleTextSize,0);
titleTextColor = ta.getInt(R.styleable.topBar_titleTextColor,0); //为右按钮的属性赋值
rightText = ta.getString(R.styleable.topBar_rightText);
rightBackground = ta.getDrawable(R.styleable.topBar_rightBackground);
rightTextColor = ta.getInt(R.styleable.topBar_rightTextColor,0); //使用完TypedArray之后需要调用其recycle()方法,以便重用
ta.recycle(); //实例化三个控件
leftBtn = new Button(context);
textView = new TextView(context);
rightBtn = new Button(context); //设置左按钮的属性
leftBtn.setText(leftText);
leftBtn.setBackground(leftBackground);
leftBtn.setTextColor(leftTextColor);
//设置文本框的属性
textView.setText(tbTitle);
textView.setTextSize(titleTextSize);
textView.setTextColor(titleTextColor);
textView.setGravity(Gravity.CENTER);
//设置右按钮的属性
rightBtn.setText(rightText);
rightBtn.setBackground(rightBackground);
rightBtn.setTextColor(rightTextColor); //设置此自定义控件的背景颜色
setBackgroundColor(0xFFF59563); //实例化左按钮的布局属性
leftBtnLayoutParams = new LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT);
//设置左按钮靠左显示
leftBtnLayoutParams.addRule(RelativeLayout.ALIGN_PARENT_LEFT,TRUE);
//将左按钮添加到本自定义控件中
addView(leftBtn,leftBtnLayoutParams); //同上
rightBtnLayoutParams = new LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT);
rightBtnLayoutParams.addRule(RelativeLayout.ALIGN_PARENT_RIGHT,TRUE);
addView(rightBtn,rightBtnLayoutParams); //同上
textViewLayoutParams = new LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.MATCH_PARENT);
textViewLayoutParams.addRule(RelativeLayout.CENTER_IN_PARENT,TRUE);
addView(textView,textViewLayoutParams); //回调左按钮的监听事件
leftBtn.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
listener.leftBtnOnClick();
}
}); //回调右按钮的监听事件
rightBtn.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
listener.rightBtnOnClick();
}
}); } //当然,我们还可以添加其他控制此控件的方法,如设置左按钮是否可见等等,大家可根据自己的需求进行扩展
public void setLeftBtnVisible(boolean isVisible){
leftBtn.setVisibility(isVisible ? VISIBLE : INVISIBLE);
}
}
.引用自定义的View
activity_main.xml
<?xml version="1.0" encoding="utf-8"?> <!--
使用自定义的控件的属性需要先添加命名空间
xmlns:cbt="http://schemas.android.com/apk/res-auto"
其中"cbt"可以任意指定,但是不能与系统的命名空间相同
在Android Studio中如上用res-auto,
在Eclipse需要在res后指定完整包名,如:
xmlns:cbt="http://schemas.android.com/apk/res/scratchcard.cbt.com.learnuserdefinedview.TopBar"
--> <LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:cbt="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
tools:context="scratchcard.cbt.com.learnuserdefinedview.MainActivity">
<!-- 添加自定义控件及属性 -->
<scratchcard.cbt.com.learnuserdefinedview.TopBar
android:id="@+id/topbar"
android:layout_width="wrap_content"
android:layout_height="40dp"
cbt:leftText = "BACK"
cbt:leftBackground = "@android:color/holo_blue_bright"
cbt:leftTextColor = "#FFFFFF" cbt:tbTitle = "自定义标题"
cbt:titleTextSize = "10sp"
cbt:titleTextColor = "#000000" cbt:rightText = "MORE"
cbt:rightBackground = "@android:color/holo_blue_bright"
cbt:rightTextColor = "#FFFFFF"/> </LinearLayout>
MainActivity.java
package scratchcard.cbt.com.learnuserdefinedview; import android.app.Activity;
import android.support.annotation.Nullable;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.util.Log;
import android.view.ViewTreeObserver;
import android.widget.Button;
import android.widget.Toast;
import scratchcard.cbt.com.learnuserdefinedview.TopBar.TopBarBtnsOnClickListener; public class MainActivity extends Activity {
//创建自定义控件
private TopBar topBar;
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
//初始化自定义控件
topBar = (TopBar) findViewById(R.id.topbar);
//为自定义控件添加按钮的监听事件
topBar.setOnTopBarBtnsClick(new TopBarBtnsOnClickListener() {
@Override
public void leftBtnOnClick() {
Toast.makeText(MainActivity.this,"LEFT",Toast.LENGTH_SHORT).show();
}
@Override
public void rightBtnOnClick() {
Toast.makeText(MainActivity.this,"RIGHT",Toast.LENGTH_SHORT).show();
}
}); }
}
运行项目后点击左边按钮: 点击右边按钮:

至此,整个自定义控件就已经完成了.虽然效果有些寒碜,但是麻雀虽小,五脏俱全.主要是通过这个实例使大家掌握自定义组合控件的过程与方法.学会了创建自定义控件的方法之后可以举一反三完成自己的漂亮的作品.
完整源码 : 点击下载
Android自定义组合控件详细示例 (附完整源码)的更多相关文章
- 014 Android 自定义组合控件
1.需求介绍 将已经编写好的布局文件,抽取到一个类中去做管理,下次还需要使用类似布局时,直接使用该组合控件的对象. 优点:可复用. 例如要重复利用以下布局: <RelativeLayout an ...
- Android自定义组合控件
今天和大家分享下组合控件的使用.很多时候android自定义控件并不能满足需求,如何做呢?很多方法,可以自己绘制一个,可以通过继承基础控件来重写某些环节,当然也可以将控件组合成一个新控件,这也是最方便 ...
- Android自定义组合控件内子控件无法显示问题
今天自定义了一个组合控件,与到了个奇葩问题: 我自定义了一个RelativeLayout,这个layout内有多个子控件.但奇怪的是这些子控件一直显示不出来.调试了一下午,竟然是因为在获取(infla ...
- (转)android自定义组合控件
原文地址:http://mypyg.iteye.com/blog/968646 目标:实现textview和ImageButton组合,可以通过Xml设置自定义控件的属性. 1.控件布局:以Linea ...
- android 自定义组合控件 顶部导航栏
在软件开发过程中,经常见到,就是APP 的标题栏样式几乎都是一样的,只是文字不同而已,两边图标不同.为了减少重复代码,提高效率, 方便大家使用,我们把标题栏通过组合的方式定义成一个控件. 例下图: 点 ...
- Android自定义组合控件:UIScrollLayout(支持界面滑动及左右菜单滑动)
一.前言: 我之前很早的时候,写过一篇<左右滑出菜单>的文章: http://blog.csdn.net/qingye_love/article/details/8776650 用的是对V ...
- Android 自定义组合控件
1, you need to add this kind of code to the constructors of your custom view which must extend ViewG ...
- Android Studio自定义组合控件
在Android的开发中,为了能够服用代码,会把有一定共有特点的控件组合在一起定义成一个自定义组合控件. 本文就详细讲述这一过程.虽然这样的View的组合有一个粒度的问题.粒度太大了无法复用,粒度太小 ...
- Android中自定义组合控件
Android中自定义控件的情况非常多,一般自定义控件可以分为两种:继承控件及组合控件.前者是通过继承View或其子类,重写方法实现自定义的显示及事件处理方式:后者是通过组合已有的控件,来实现结构的简 ...
随机推荐
- MySQL查找SQL耗时瓶颈 SHOW profiles
http://blog.csdn.net/k_scott/article/details/8804384 1.首先查看是否开启profiling功能 SHOW VARIABLES LIKE '%pro ...
- keras框架的CNN手写数字识别MNIST
参考:林大贵.TensorFlow+Keras深度学习人工智能实践应用[M].北京:清华大学出版社,2018. 首先在命令行中写入 activate tensorflow和jupyter notebo ...
- python递归和二分法
一.递归 1.递归就是自己调用自己 def fn(n): print(n) fn(n+1) fn(1) #递归深度官方1000 一般都递归到998 2.树形结构的遍历 import os def fn ...
- Jetty 9的使用
参考来源:https://www.cnblogs.com/empireghost/p/3522834.html
- 746. Min Cost Climbing Stairs
两种方法,核心思想都一样,求出走到每一步上的最小开销,直到最后一步和倒数第二步,比较其最小值返回即可. 方法一,用一个辅助的容器 class Solution { public: int minCos ...
- BEM思想之彻底弄清BEM语法
BEM的意思就是块(block).元素(element).修饰符(modifier),是由Yandex团队提出的一种前端命名方法论.这种巧妙的命名方法让你的CSS类对其他开发者来说更加透明而且更有意义 ...
- 学以致用二---配置Centos7.2 基本环境
Centos 7 虚拟机安装好后,接下来该配置环境了. 一.查看系统版本 cat /etc/redhat-release 二.修改主机名 /etc/hostname 注意,hostname里的内容为l ...
- oss上传大文件
最近公司做工程项目,实现文件云存储上传. 网上找了一天,发现网上很多代码都存在相似问题,最后终于找到了一个满足我需求的项目. 工程如下: 这里对项目的文件传输功能做出分析,怎么实现文件上传的,如何进行 ...
- OC语言-runtime
参考博客 IOS高级开发-Runtime(一) http://blog.csdn.net/lizhongfu2013/article/details/9496705 apple官方参考 Object- ...
- hdu 1130 How Many Trees? 【卡特兰数】
题目 题意:给你一个数字n,问你将1~n这n个数字,可以组成多少棵不同的二叉搜索树. 1,2,5,14--根据输出中的规律可以看出这是一个卡特兰数的序列.于是代用卡特兰数中的一个递推式: 因为输入可取 ...