Android 自定义View控件

一、简介

  在自定义View时,我们通常会重写onDraw()方法来绘制View的显示内容。如果,该View还需要使用wrap_content属性,那么还必须重写onMeasure()方法。另外,通过自定义attrs属性,还可以设置新的属性配置值。

  在View中通常有以下一些比较重要的回调方法:

  • onFinisInflate():从XML加载组件后回调;
  • onSizeChanged():组件大小改变时回调;
  • onMeasure():回调该方法来进行测量;
  • onLayout():回调该方法来确定显示位置;
  • onTouchEvent():监听到触摸事件时回调;

  当然,创建自定义View的时候,并不需要重写所有方法,只需要重写特定条件的回调方法即可。

  通常情况下,有以下三种方法来实现自定义的控件:

  • 对现有控件进行拓展;
  • 通过组合来实现新的控件;
  • 重写View来实现全新的控件;

二、实例:

一、创建复合控件

  1. 定义属性

  为一个View提供可自定义的属性非常简单,只需要在res资源目录的values目录下创建一个attrs.xml的属性定义文件,并在该文件中通过如下代码定义相应的属性即可。

 1 <?xml version="1.0" encoding="utf-8"?>
 2 <resources>
 3     <declare-styleable name="TopBar">
 4         <attr name="title" format="string" />
 5         <attr name="titleTextSize" format="dimension" />
 6         <attr name="titleTextColor" format="color" />
 7         <attr name="leftTextColor" format="color" />
 8         <attr name="leftBackground" format="reference|color" />
 9         <attr name="leftText" format="string" />
10         <attr name="rightTextColor" format="color" />
11         <attr name="rightBackGround" format="reference|color" />
12         <attr name="rightText" format="string" />
13     </declare-styleable>
14 </resources>

  我们在代码中通过<declare-styleable>标签声明了使用自定义属性,并通过name属性来确定引用的名称。最后,通过<attr>标签来声明具体的自定义属性,比如:标题文字、颜色、大小等属性。并通过format属性来指定属性的类型。需要注意的是,有些属性可以是颜色属性,也可以是引用属性。比如:按钮的背景,可以把其指定为具体颜色,也可以把它指定为一张图片,所以,使用“|”来分隔不同的属性——"reference|color"。

  在构造方法中,通过如下代码来获取在XML布局文件中自定义的那些属性,即与我们使用系统提供的那些属性一样。

1 /**
2  * attrs : 属性设置
3  * R.styleable.TopBar : 在attrs.xml文件中,配置的属性
4  */
5 TypeArray ta = context.obtainStyledAttributes(attrs, R.styleable.TopBar);

  示例代码如下所示:

 1 public class TopBar extends View
 2 {
 3     protected Color mLeftTextColor;
 4
 5     public TopBar(Context context)
 6     {
 7         this(context, null);
 8     }
 9
10     public TopBar(Context context, AttributeSet attrs)
11     {
12         super(context, attrs);
13         // 通过这个方法将在attrs.xml文件中,定义的<declare-styleable>的所有属性的值存储到TypedArray中
14         TypedArray ta = context.obtainStyledAttributes(attrs, R.styleable.TopBar);
15
16         // 在TypedArray中,取出对应的值来为要设置的属性赋值
17         mLeftTextColor = ta.getColor(R.styleable.TopBar_leftTextColor, 0);
18
19         // 获取完TypedArray的值后,一般要调用recyle方法来避免重新创建的时候的错误
20         ta.recycle();
21     }
22 }

  PS: 需要注意的是,当获取完所有的属性值后,需要调用TypedArray的recyle()方法来完成资源的回收。

  2. 组合控件
 1 public class TopBar extends RelativeLayout
 2 {
 3     protected String mTitle;
 4     protected float mTitleTextSize;
 5     protected int mTitleTextColor;
 6     protected int mLeftTextColor;
 7     protected Drawable mLeftBackground;
 8     protected String mLeftText;
 9     protected int mRightTextColor;
10     protected Drawable mRightBackground;
11     protected String mRightText;
12
13     public Button mLeftButton;
14     public TextView mTitleView;
15     public Button mRightButton;
16
17     protected RelativeLayout.LayoutParams mLeftLayoutParams;
18     protected RelativeLayout.LayoutParams mTitleLayoutParams;
19     protected RelativeLayout.LayoutParams mRightLayoutParams;
20
21     public TopBar(Context context)
22     {
23         this(context, null);
24     }
25
26     public TopBar(Context context, AttributeSet attrs)
27     {
28         super(context, attrs);
29         // 通过这个方法将在attrs.xml文件中,定义的<declare-styleable>的所有属性的值存储到TypedArray中
30         TypedArray ta = context.obtainStyledAttributes(attrs, R.styleable.TopBar);
31
32         // 在TypedArray中,取出对应的值来为要设置的属性赋值
33         // left button
34         mLeftTextColor = ta.getColor(R.styleable.TopBar_leftTextColor, 0);
35         mLeftBackground = ta.getDrawable(R.styleable.TopBar_leftBackground);
36         mLeftText = ta.getString(R.styleable.TopBar_leftText);
37
38         // title
39         mTitleTextSize = ta.getDimension(R.styleable.TopBar_titleTextSize, 10);
40         mTitleTextColor = ta.getColor(R.styleable.TopBar_titleColor, 0);
41         mTitle = ta.getString(R.styleable.TopBar_titleText);
42
43         // right button
44         mRightTextColor = ta.getColor(R.styleable.TopBar_rightTextColor, 0);
45         mRightBackground = ta.getDrawable(R.styleable.TopBar_rightBackGround);
46         mRightText = ta.getString(R.styleable.TopBar_rightText);
47
48         // 获取完TypedArray的值后,一般要调用recyle方法来避免重新创建的时候的错误
49         ta.recycle();
50
51         initView(context);
52     }
53
54     private void initView(Context context)
55     {
56         mLeftButton = new Button(context);
57         mTitleView = new TextView(context);
58         mRightButton = new Button(context);
59
60         mLeftButton.setText(mLeftText);
61         mLeftButton.setBackground(mLeftBackground);
62         mLeftButton.setTextColor(mLeftTextColor);
63
64         mTitleView.setText(mTitle);
65         mTitleView.setTextColor(mTitleTextColor);
66         mTitleView.setTextSize(mTitleTextSize);
67
68         mRightButton.setText(mRightText);
69         mRightButton.setBackground(mRightBackground);
70         mRightButton.setTextColor(mRightTextColor);
71
72         mLeftLayoutParams = new LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.MATCH_PARENT);
73         mLeftLayoutParams.addRule(ALIGN_PARENT_LEFT, TRUE);
74         addView(mLeftButton, mLeftLayoutParams);
75
76         mTitleLayoutParams = new LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.MATCH_PARENT);
77         mTitleLayoutParams.addRule(CENTER_IN_PARENT, TRUE);
78         addView(mTitleView, mTitleLayoutParams);
79
80         mRightLayoutParams = new LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.MATCH_PARENT);
81         mRightLayoutParams.addRule(ALIGN_PARENT_RIGHT, TRUE);
82         addView(mRightButton, mRightLayoutParams);
83     }
84
85 }
  3. 定义接口

  定义接口对象,在TopBar控件中,实现左右按钮的点击事件,调用接口方法:

 1 // 定义接口
 2 mLeftButton.setOnClickListener(new OnClickListener()
 3 {
 4     @Override
 5     public void onClick(View v)
 6     {
 7         mListener.leftClick();
 8     }
 9 });
10
11 mRightButton.setOnClickListener(new OnClickListener()
12 {
13     @Override
14     public void onClick(View v)
15     {
16         mListener.rightClick();
17     }
18 });
19
20 ......
21
22 // 左右按钮接口类
23 public interface TopBarClickListener
24 {
25     void leftClick();
26     void rightClick();
27 }
28
29 // 设置左右按钮点击事件接口实现的实例
30 public void setOnTopBarClickListener(TopBarClickListener topBarClickListener)
31 {
32     mListener = topBarClickListener;
33 }
  4. 引用UI模板

  在引用UI模板前,需要指定引用第三方控件的命名空间。在布局文件中,如下所示:

1 xmlns:androi="http://schemas.android.com/apk/res/android"

  这行代码就是在指定引用的名字控件xmlns,即xml namespace。这里指定了命名空间为“android”,因此,在接下来使用系统属性的时候,才可以使用“android:”来引用Android的系统属性。同样地,使用自定义的属性,那么就需要创建自己的命名空间,在Android Studio中,第三方控件 都使用如下代码引入命名空间:

1 xmlns:custom="http://schemas.android.com/apk/res-auto"

  这里引用的第三方命名空间为custom,之后在XML文件中使用自定义的属性时,就可以通过这个命名空间来引用,代码如下所示:

 1 <?xml version="1.0" encoding="utf-8"?>
 2 <com.naray.radialview.View.TopBar
 3     xmlns:android="http://schemas.android.com/apk/res/android"
 4     xmlns:custom="http://schemas.android.com/apk/res-auto"
 5     android:layout_width="wrap_content"
 6     android:layout_height="wrap_content"
 7     custom:titleText="自定义控件"
 8     custom:titleColor="#da0c0c"
 9     custom:titleTextSize="18sp"
10     custom:leftBackground="#999999"
11     custom:leftTextColor="#da0c0c"
12     custom:leftText="back"
13     custom:rightBackGround="#999999"
14     custom:rightTextColor="#da0c0c"
15     custom:rightText="more">
16
17 </com.naray.radialview.View.TopBar>

  使用自定义的View与系统原生的View最大的区别就是在申明控件时,需要指定完整的包名,而在引用自定义的属性时,需要使用自定义的xmlns名字。

二、重写View来实现全新的控件

三、自定义ViewGroup

时间: 2024-10-10 07:50:05

Android 自定义View控件的相关文章

Android自定义View控件

转自:http://blog.csdn.net/lvwenbo0107/article/details/50542597 写的够详细了 为什么要自定义控件 1.特定的显示风格. 2.处理特有的用户交互.(textView支持一些滑动功能) 3.优化我们的布局.(嵌套布局绘制比较慢) 4.封装.(tab页按钮不好看) 如何自定义控件 1.自定义属性声明与获取. 2.测量onMeasure. 3.布局onLayout(ViewGroup才需要) 4.绘制onDraw 5.onTouchEvent 6

Android 自定义组合控件小结

引言 接触Android UI开发的这段时间以来,对自定义组合控件有了一定的了解,为此小结一下,本文小结内容主要讨论的是如何使用Android SDK提供的布局和控件组成一个功能完整组合控件并将其封装为面向对象的类,而并非讨论如何继承自SDK提供的控件类(比如TextView),对其进行自定义扩展的问题. 进入正题前,我们先来看一组功能需求 假设在手机需求上,那么如上三个界面我们可以使用三个Activity,每个Activity一个布局文件,实现起来比较独立,但是假设在Android pad上要

Android自定义用户控件简单范例(一)

一款优秀的移动应用需要具有自己独特统一的风格,通常情况下UI设计师会根据产品需求和使用人群的特点,设计整体的风格,界面的元素和控件的互效果.而原生态的Android控件为开发人员提供的是最基本的积木元素,如果要准确地传递统一的视觉效果和交互体验,对控件的自定义使用是非常有必要的. 这篇文章通过一个简单的从Java后台程序中进行创建的示例来说明Android自定义控件的运行原理. <LinearLayout xmlns:android="http://schemas.android.com/

Android自定义用户控件简单范例(二)

对于完全由后台定制的控件,并不是很方便其他人的使用,因为我们常常需要看到控件放到xml界面上的效果,并根据效果进行布局的调整,这就需要一个更加标准的控件制作流程: 我们的自定义控件和其他的控件一样,应该写成一个类,而这个类的属性是是有自己来决定的. 我们要在res/values目录下建立一个attrs.xml的文件,并在此文件中增加对控件的属性的定义. 使用AttributeSet来完成控件类的构造函数,并在构造函数中将自定义控件类中变量与attrs.xml中的属性连接起来. 在自定义控件类中使

Android自定义组合控件--底部多按钮切换

效果图: 现在市场上大多数软件都是类似于上面的结构,底部有几个按钮用于切换到不同的界面.基于OOP思想,我想把下面的一整块布局封装成一个类,也就是我们的自定义组合控件-底部多按钮切换布局,我把它叫做BottomLayout 看上面的布局,几个按钮横向排列,我们先看一下布局 最外面LinearLayout 方向 horizontal,然后5个weight相同的RelativeLayout,每个RelativeLayout里面有一个Button(用了显示选中状态)个ImageView(用来显示红点)

android自定义倒计时控件示例

这篇文章主要介绍了Android秒杀倒计时自定义TextView示例,大家参考使用吧 自定义TextView控件TimeTextView代码: 复制代码 代码如下: import android.content.Context;import android.content.res.TypedArray;import android.graphics.Paint;import android.text.Html;import android.util.AttributeSet;import and

android 自定义组合控件

自定义控件是一些android程序员感觉很难攻破的难点,起码对我来说是这样的,但是我们可以在网上找一些好的博客关于自定义控件好好拿过来学习研究下,多练,多写点也能找到感觉,把一些原理弄懂,今天就讲下自定义组合控件,这个特别适合在标题栏或者设置界面,看下面图: 就非常适合使用组合控件了,现在写一个玩玩: activity_main.xml <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"

Android自定义组合控件--图片加文字,类似视频播放软件的列表

分四步来写: 1,组合控件的xml; 2,自定义组合控件的属性; 3,自定义继承组合布局的class类,实现带两参数的构造器; 4,在xml中展示组合控件. 具体实现过程: 一.组合控件的xml 我接触的有两种方式,一种是普通的Activity的xml:一种是父节点为merge的xml.我项目中用的是第一种,但个人感觉第二种好,因为第一种多了相对或者绝对布局层. 我写的 custom_pictext.xml <?xml version="1.0" encoding="u

Android自定义UI控件(简单方便版,但不灵活)

这种方法的优点就是简单,容易理解,适合开发一些不经常用到的自定义UI控件 缺点就是比较不灵活,如果其他应用想使用这个控件的话得改很多 简单来说,这个方法是用来做成品的,下一篇的方法是用来做模板的. 先看成品,这是一个标题栏控件: 由左右两个按钮和中一个TextView组成: 实现方法: 第一步:定义一个xml文件,用来设计你自定义控件的雏形 示例代码:文件名为title 1 <?xml version="1.0" encoding="utf-8"?> 2