Android 自定义控件开发入门(一)
那么怎样来创建一个新的控件呢?
这得看需求是怎样的了。
1.需要在原生控件的基本功能上进行扩展,这个时候你只需要继承并对控件进行扩展。通过重写它的事件,onDraw ,但是始终都保持都父类方法的调用。如从已有的高级控件上继承,例如继承一个TextView。
2.需要几个控件的功能的加和,这个时候要把控件组合起来,就是通过合并几个控件来生成一个新控件。比如在ListView中用适配器来将多种控件有机的结合在一起,又如写一个控件是多个控件的组合,一般是自定义布局,可以用一个类继承一个布局。这个布局中包含多个控件。
3.白手起家自己创建一个新的控件。即直接从View,ViewGroup开始绘制控件
4.另外大家不要忘了,还有一个好用的东西<include>标签。 在一个项目中我们可能会需要用到相同的布局设计,如果都写在一个xml文件中,代码显得很冗余,并且可读性也很差,所以我们可以把相同布局的代码单独写成一个模块,然后用到的时候可以通过<include /> 标签来重用layout代码。
作过Android 应用开发的朋友都知道,Android的UI界面都是由View和ViewGroup及其派生类组合而成的。基于安卓UI设计原理,我们作为开发者,完全能够按照自己的意愿开发出项目定制的组件。其中,View是所有UI组件的基类,而ViewGroup是容纳这些组件的容器,其本身也是从View派生出来的。AndroidUI界面的一般结构可参见下面的示意图:
可见,作为容器的ViewGroup可以包含作为叶子节点的View,也可以包含作为更低层次的子ViewGroup,而子ViewGroup又可以包含下一层的叶子节点的View和ViewGroup。事实上,这种灵活的View层次结构可以形成非常复杂的UI布局,开发者可据此设计、开发非常精致的UI界面。
ViewGroup可以通过重写onMeasure,onLayout为加入其中的View进行布局和处理,功能十分强大,我们这次先学习View类派生自定义组件:
View组件的作用类似于JAVA中Swing里的Panel,是一个矩形的空白区域,不带有任何内容,对于Android应用的其他UI控件来说,都是继承了View组件,然后绘制出来的。所以我们通过View子类并重写View类的方法来派生我们自己的控件。
Android自定义View实现很简单:
继承View,重写构造函数、onDraw,(onMeasure)等函数,下面会逐一列举。
如果自定义的View需要有自定义的属性,需要在values下建立attrs.xml。在其中定义你的属性。在使用到自定义View的xml布局文件中需要加入xmlns:前缀="http://schemas.android.com/apk/res/你的自定义View所在的包路径".在使用自定义属性的时候,使用前缀:属性名,如my:textColor="……"。
让我们先看一下View类的方法:
Category |
Methods |
Description |
Creation |
Constructors |
There is a form of the constructor that are called when the view is created from code and a form that is called when the view is inflated from a layout file. The second form should parse and apply any attributes defined in the layout file. |
onFinishInflate() |
Called after a view and all of its children has been inflated from XML. |
|
Layout |
onMeasure(int, int) |
Called to determine the size requirements for this view and all of its children. |
onLayout(boolean, int, int, int, int) |
Called when this view should assign a size and position to all of its children. |
|
onSizeChanged(int, int, int, int) |
Called when the size of this view has changed. |
|
Drawing |
onDraw(android.graphics.Canvas) |
Called when the view should render its content. |
Event processing |
onKeyDown(int, KeyEvent) |
Called when a new hardware key event occurs. |
onKeyUp(int, KeyEvent) |
Called when a hardware key up event occurs. |
|
onTrackballEvent(MotionEvent) |
Called when a trackball motion event occurs. |
|
onTouchEvent(MotionEvent) |
Called when a touch screen motion event occurs. |
|
Focus |
onFocusChanged(boolean, int, android.graphics.Rect) |
Called when the view gains or loses focus. |
onWindowFocusChanged(boolean) |
Called when the window containing the view gains or loses focus. |
|
Attaching |
onAttachedToWindow() |
Called when the view is attached to a window. |
onDetachedFromWindow() |
Called when the view is detached from its window. |
|
onWindowVisibilityChanged(int) |
Called when the visibility of the window containing the view has changed. |
通常可能需要重写以下方法:
1.构造器,至少用来获取Context
2.onFinishlnflate()这是一个回调方法, 当应用从 XML 布局文件加载该组件并利用
它来构建界面之后, 该方法就会被回调。
3.onMeasure(int,int):调用该方法来检测View组件及它所包含的所有子组件的大小.
4.onlayout(boolean,int,int,int,int):当该组件需要分配其子组件的位置、大小时,
该方法就会被回调. View类中布局发生改变时会调用的方法,这个方法是所有View、ViewGroup及其派生类都具有的方法,重载该类可以在布局发生改变时作定制处理,这在实现一些特效时非常有用。
5.onSizeChanged(int,int, int, int):当该组件的大小被改变时回调该方法.
6.onDraw(canves): 当该组件将要绘制它的内容时回调该方法迸行绘制. View类中用于重绘的方法,这个方法是所有View、ViewGroup及其派生类都具有的方法,也是Android UI绘制最重要的方法。开发者可重载该方法,并在重载的方法内部基于参数canvas绘制自己的各种图形、图像效果。
7.onKeyDown(int,KeyEvent): 当某个键被按下时触发该方法.
8.onKayUp(int,KeyEvent), 当松开某个键时触发该方法.
9.onTrackballEvent (MotionEvent): 当发生轨迹球事件时触发该方法.
10.onTouchEvent (MotionEvent): 当发生触摸屏事件时触发该方法.
11.onWindowFocuschanged(boolean): 当该组件得到、失去焦点时触发该方法.
12.onAttachedToWindow():当把该组件放入某个窗口时触发该方法.
13.onDetachedFromWindow(): 当把该组件从某个窗口上分离时触发该方法.
14.onWindowVisibilityChanged(int):当包含该组件的窗口的可见性发生改变时触发该
方法.
另外再补充两个ViewGroup类经常重载的方法:
1.protected void dispatchDraw(Canvas canvas):ViewGroup类及其派生类具有的方法,这个方法主要用于控制子View的绘制分发,重载该方法可改变子View的绘制,进而实现一些复杂的视效。
2.protected boolean drawChild(Canvas canvas, View child, long drawingTime)):ViewGroup类及其派生类具有的方法,这个方法直接控制绘制某局具体的子view,重载该方法可控制具体某个具体子View。
在需要开发自定义View的时候,我们不需要列举出上面所有的方法,,而是可以根据业务需要来有选择的使用·上面的方法,下面我们看一个简单的示例程序,在这个示例程序里面我们只需要重写onDraw方法就可以了!
示例程序一:
我们要写一个跟随手指移动的小球,思路很简单,只要获取到用户点击屏幕的位置,并且在该位置处重绘小球即可:
下面我们看一下程序:
我注释写的比较清楚,我就说的简略一点:
首先我们写一个类DrawView,也就是我们自定义的控件,继承自View
然后我们先写出构造器,获取到Context,这里如果用只含有Context的构造器会在xml里调用控件的时候出错,详情请看我的另外一篇博文:
http://blog.csdn.net/sunmc1204953974/article/details/38101057
下面我们开始写:
- // 构造方法
- public DrawView(Context context,AttributeSet attrs){
- super(context,attrs);
- }
- // 重写ondraw方法
- @Override
- public void onDraw(Canvas canvas){
- super.onDraw(canvas);
- // 创建画笔
- Paint paint = new Paint();
- // 设置画笔颜色
- paint.setColor(Color.RED);
- // 画出小球
- canvas.drawCircle(circleX, circleY, circleR, paint);
- }
然后不要忘了设置这些数据的setter和getter,因为我们需要再使用这个View的时候加上监听才可以:
- // get set 方法
- public float getCircleX() {
- return circleX;
- }
- public void setCircleX(float circleX) {
- this.circleX = circleX;
- }
- public float getCircleY() {
- return circleY;
- }
- public void setCircleY(float circleY) {
- this.circleY = circleY;
- }
- public float getCircleR() {
- return circleR;
- }
- public void setCircleR(float circleR) {
- this.circleR = circleR;
- }
这样我们的一个简单地自定控件就大功告成了,下面是该类的完整代码:
- package com.example.moveball;
- import android.content.Context;
- import android.graphics.Canvas;
- import android.graphics.Color;
- import android.graphics.Paint;
- import android.util.AttributeSet;
- import android.view.View;
- public class DrawView extends View{
- private float circleX = 40;
- private float circleY = 50;
- private float circleR = 15;
- // 构造方法
- public DrawView(Context context,AttributeSet attrs){
- super(context,attrs);
- }
- // 重写ondraw方法
- @Override
- public void onDraw(Canvas canvas){
- super.onDraw(canvas);
- // 创建画笔
- Paint paint = new Paint();
- // 设置画笔颜色
- paint.setColor(Color.RED);
- // 画出小球
- canvas.drawCircle(circleX, circleY, circleR, paint);
- }
- // get set 方法
- public float getCircleX() {
- return circleX;
- }
- public void setCircleX(float circleX) {
- this.circleX = circleX;
- }
- public float getCircleY() {
- return circleY;
- }
- public void setCircleY(float circleY) {
- this.circleY = circleY;
- }
- public float getCircleR() {
- return circleR;
- }
- public void setCircleR(float circleR) {
- this.circleR = circleR;
- }
- }
之后我们就是像平时使用安卓原生控件那样使用就可以了,我们看一下Activity的代码:
- package com.example.moveball;
- import android.os.Bundle;
- import android.app.Activity;
- import android.view.Menu;
- import android.view.MotionEvent;
- import android.view.View;
- import android.view.View.OnTouchListener;
- public class MainActivity extends Activity {
- // 定义DrawView组件
- DrawView drawView = null;
- @Override
- protected void onCreate(Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
- setContentView(R.layout.activity_main);
- // 创建DrawView组件
- drawView = (DrawView)this.findViewById(R.id.drawView);
- // 为DrawView组件绑定Touch事件
- drawView.setOnTouchListener(new OnTouchListener() {
- @Override
- public boolean onTouch(View arg0, MotionEvent event) {
- // 获取坐标并改变小球的坐标
- drawView.setCircleX(event.getX());
- drawView.setCircleY(event.getY());
- // 通知draw组件重绘
- drawView.invalidate();
- // 返回true表明被执行
- return true;
- }
- });
- }
- }
以及xml格式的布局文件:
- <?xml version="1.0" encoding="utf-8"?>
- <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:tools="http://schemas.android.com/tools"
- android:layout_width="match_parent"
- android:layout_height="match_parent"
- tools:context=".MainActivity" >
- <com.example.moveball.DrawView
- android:id="@+id/drawView"
- android:layout_width="match_parent"
- android:layout_height="match_parent" >
- </com.example.moveball.DrawView>
- </RelativeLayout>
这样一个简单的例子就呈现在大家面前了,无论是多么复杂的自定义控件,思路总是这样子的,大家是不是觉得怪怪的,对了,作为一个控件,我们居然还要为了他的实现为其增加麻烦的监听,这就是因为我们重写的方法太少的原因,下一讲再给大家介绍一个经常重写的方法:publicboolean onTouchEvent (MotionEvent event)。
源代码上面已经很详细了,我在最后一篇的最后还会发一个工程上来,欢迎大家一起学习!
我也还是学生,写的不好或者有问题的地方还请多多指教~
Android 自定义控件开发入门(一)相关推荐
- Android自定义控件开发入门与实战(1)绘图基础
今天从leader那里拿到了启舰大神写的<自定义控件开发入门与实战>这本书,据说看完了,至少写起自定义view也不会慌. 最重要的是多练,所以这本书基本设计到的我没有涉及过的控件开发(之前 ...
- Android自定义控件开发入门与实战(11)Xfermode,Android程序员如何有效提升学习效率
mPaint = new Paint(); mPaint.setColor(Color.BLACK); mBitmap = BitmapFactory.decodeResource(getResour ...
- Android自定义控件开发入门与实战(7)SVG动画,android底层架构
move to (50,23) line to(100,25) 而坐标并不是用width和height的坐标,而是viewportWidth和viewportHeight的坐标,(50,23)中50表 ...
- Android-史上最优雅的实现文件上传、下载及进度的监听,android自定义控件开发入门与实战
注:如果需要对Http的返回值做解析,可在使用uploadProgress操作符时,传入一个解析器Parser 下载 //文件存储路径 String destPath = getExternalCac ...
- Android自定义控件开发入门与实战(6)路径动画,android脚本开发工具
前面几章所讲的内容其实都只是比较普通.简单的动画,这章开始学习较难.较为有深度.也比较可以实现更加炫酷效果的动画,通过PathMeasure和SVG动画来实现. PathMeasure实现路径动画 P ...
- Android自定义控件开发入门与实战(15)SurfaceView,看完就能找到工作
SurfaceHolder surfaceHolder = getHolder(); Canvas canvas1 = surfaceHolder.lockCanvas(); //绘图操作 - sur ...
- Android自定义控件开发系列(零)——基础原理篇
在后边的文章中发现在说Android自定义时,有时候要重复解释很多东西,所以想想返回来增加一篇"基础原理篇",直接进入正题吧-- 首先的问题是:在Android项目开发中,什么时候 ...
- 5G 时代的 Android App 开发入门与项目实战
随着移动互联网的持续发展,Android系统从智能手机逐步拓展到平板电脑.智能电视.车载大屏.智能家居.智能手表等诸多设备,Android开发依然是前景可期的IT岗位. 当然,整个社会正在迈向5G时代 ...
- 《Android应用开发入门经典(第3版)》——第6.1节创建演示应用
本节书摘来自异步社区<Android应用开发入门经典(第3版)>一书中的第6章,第6.1节创建演示应用,作者 [美]Carmen Delessio , Lauren Darcey , Sh ...
最新文章
- 在ATS 5.3.0上开启stats_over_http插件
- 一个在raw里面放着数据库文件的网上例子
- 深度学习会议论文不好找?这个ConfTube网站全都有
- 通过LDAP验证Active Directory服务
- log4j升级到logback
- thinkphp mysql 中文 问号_thinkphp分页中文参数乱码解决
- Windows用WinDbg分析蓝屏dump文件查找原因(转)
- 使用 vs 2008 宏制作自动注释工具
- android aes256加密算法,Android中AES256加密的实现
- SLIC超像素分割详解(一):简介
- MavLink 库 c++环境搭建及解ADS-B消息教程
- Spring乱码问题解决
- SM2 加解密注意事项
- 华为数通HCIA学习笔记之OSI参考模型TCP/IP模型
- Error parsing HTTP request header...java.lang.IllegalArgumentException: Invalid character found in m
- 大数据学习路线-入门精简
- Python加密工具包pycrypto的安装
- excel打开密码忘记了_如何设置EXCEL文件打开和编辑密码
- 论文阅读笔记:《一种改进的图卷积网络半监督节点分类》
- 深圳软件测试培训:软件测试的需求评审