Android自定义控件(一)

来源:互联网 发布:大数据架构师是什么 编辑:程序博客网 时间:2024/06/07 09:34

出处:http://www.cnblogs.com/0616--ataozhijia/p/4003380.html

    http://blog.csdn.net/lmj623565791/article/details/24252901/

开发自定义控件的步骤

1、了解View工作原理
2、编写继承自view的子类

3、为自定义View增加属性

4、绘制控件

5、响应用户消息

6、自定义回调函数

一、view结构原理

view作为所有图形的基类,ViewGroup对view继承扩展为视图容器类。

View定义了绘图的基本操作

基本操作用三个函数完成  measure(),layout(),draw()、其内部又包含了onMeasure(),onLayout(),onDraw(),三个方法,具体操作如下:

1、measure操作

measure操作主要用于计算视图的大小,即视图的宽度和长度,在View中定义为final类型,要求子类不能修改,measure又会调用一下函数

(1)onMeasure(),视图大小将在这里最终确定,也就是说measure只是对onMeasure的包装,子类复写onMeasure()方法实现自己 计算视图大小的方式,

并通过serMeasureDimension(width,height)保存计算结果

2、layout操作

layout操作用于设置视图在屏幕中显示的位置,在View中定义为final类型,要求子类不能修改。layout函数中有两个基本操作

(1)setFrame(l,t,r,b)参数即父视图的具体坐标位置,该函数用于将这些参数保存起来。

(2)onLayout 在view中这个函数什么都不会做,提供该函数主要是为了viewGroup类型布局子视图用的。

3、draw操作

draw操作利用前两步得到的参数,将视图显示在屏幕上,在这里将完成整个视图绘制工作,子类也不应该修改该方法,因为其内部定义了绘图的基本操作。

(1)绘制背景

(2)如果视图显示渐变框,这里会做一些准备工作

(3)绘制视图本身,即调用onDraw()方法、在View中OnDraw是个空函数,也就是说具体悳视图都要复写该函数来实现自己的显示,(比如textView在这里实现绘制文字的过程)。对于ViewGroup则不需要实现该函数,因为容器是没有内容的,其包含了多个ziView,而子view已经实现了自己的绘制方法,因此只需要告诉子View绘制自己就可以了,也就是下面的dispatchDraw()方法。

(4)绘制子视图,即dispatchDraw()方法,在View中这是个空函数,具体视图不需要实现该方法,他是专门为容器类准备的,也就是容器类必须实现的方法。

(5)如果需要(应用程序调用了serVervicalFadingEdge或者setHorizontalFadingEdge),开始绘制渐变框

(6)绘制滚动条

从上面可以看书自定义View最少复写onMeasure()和onDraw()两个方法


二、View类的构造方法

创建自定义控件的三种主要实现方式,

1)继承已有的控件实现自定义控件,主要是当腰实现和已有的控件很多方面比较类似,通过对已有控件的扩展来满足要求

2)通过继承一个布局文件实现自定义控件,一般来书做组合控件时可以通过这个方式来实现

3)通过继承view;来实现自定义控件,使用GDI绘制出组件界面,一般无法通过上述两种方式来实现时用该方法。

三、自定义View增加属性的两种方法

1)在View类中定义,通过构造函数引入的AttributeSet去查找XML布局的属性名称,然后找到它对应引用的资源Id找值

public class MyView extends View{    private String mText;    private int mSrcId;    public MyView(Context context)    {        super(context);    }    public MyView(Context context, AttributeSet attrs)    {        super(context, attrs);        /**         * textId即 R.string.aaa         * mSrcId即R.drawable.daodaogou         * Src="@drawable/daodaogou"         * 所以此处没多少意义,熟悉下AttributeSet用法         */        int textId = attrs.getAttributeResourceValue(null, "Text", 0);        mSrcId = attrs.getAttributeResourceValue(null, "Src", 0);        mText = context.getResources().getText(textId).toString();    }    @Override    protected void onDraw(Canvas canvas)    {        Paint paint = new Paint();        paint.setTextSize(60);        paint.setColor(Color.RED);        InputStream inputStream = getResources().openRawResource(mSrcId);        Bitmap bitmap = BitmapFactory.decodeStream(inputStream);        int width = bitmap.getWidth();        int height = bitmap.getHeight();        canvas.drawBitmap(bitmap,0,0,paint);        canvas.drawText(mText,60,60,paint);    }}


布局文件

<?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"    android:orientation="vertical" >    <com.example.myimageview2.MyView        android:id="@+id/myView1"        android:layout_width="wrap_content"        android:layout_height="wrap_content"         Text="@string/hello_world"        Src="@drawable/xh"/></LinearLayout>

2)通过Text、Src在自定义View类的构造方法获取

public class MyImageView extends LinearLayout {    public MyImageView(Context context) {        super(context);    }    public MyImageView(Context context, AttributeSet attrs) {        super(context, attrs);        int resourceId = -1;        TypedArray typedArray = context.obtainStyledAttributes(attrs,                R.styleable.MyImageView);        ImageView iv = new ImageView(context);        TextView tv = new TextView(context);        int N = typedArray.getIndexCount();        for (int i = 0; i < N; i++) {            int attr = typedArray.getIndex(i);            switch (attr) {            case R.styleable.MyImageView_Oriental:                resourceId = typedArray.getInt(                        R.styleable.MyImageView_Oriental, 0);                this.setOrientation(resourceId == 1 ? LinearLayout.HORIZONTAL                        : LinearLayout.VERTICAL);                break;            case R.styleable.MyImageView_Text:                resourceId = typedArray.getResourceId(                        R.styleable.MyImageView_Text, 0);                tv.setText(resourceId > 0 ? typedArray.getResources().getText(                        resourceId) : typedArray                        .getString(R.styleable.MyImageView_Text));                break;            case R.styleable.MyImageView_Src:                resourceId = typedArray.getResourceId(                        R.styleable.MyImageView_Src, 0);                iv.setImageResource(resourceId > 0 ?resourceId:R.drawable.ic_launcher);                break;               }        }        addView(iv);        addView(tv);        typedArray.recycle();    }}

attrs.xml进行属性声明,文件放在values目录下

<?xml version="1.0" encoding="utf-8"?><resources>    <declare-styleable name="MyImageView">        <attr name="Text" format="reference|string"></attr>        <attr name="Oriental" >            <enum name="Horizontal" value="1"></enum>            <enum name="Vertical" value="0"></enum>        </attr>        <attr name="Src" format="reference|integer"></attr>    </declare-styleable></resources>

MainActivity的布局文件:先定义命名空间 xmlns:uview="http://schemas.android.com/apk/res/com.example.myimageview2" (com.example.myimageview2为你
在manifest中定义的包名)
然后可以像使用系统的属性一样使用:uview:Oriental="Vertical"

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"    xmlns:uview="http://schemas.android.com/apk/res/com.example.myimageview2"    xmlns:tools="http://schemas.android.com/tools"    android:layout_width="match_parent"    android:layout_height="match_parent"    android:orientation="vertical"    tools:context=".MainActivity" >    <TextView        android:layout_width="wrap_content"        android:layout_height="wrap_content"        android:text="@string/hello_world" />    <com.example.myimageview2.MyImageView        android:id="@+id/myImageView1"        android:layout_width="wrap_content"        android:layout_height="wrap_content"        uview:Text="这是一个图片说明"         uview:Src="@drawable/tw"        uview:Oriental="Vertical">    </com.example.myimageview2.MyImageView></LinearLayout>

六、自定义View的方法

onFinishInflate() 回调方法,当应用从XML加载该组件并用它构建界面之后调用的方法
onMeasure() 检测View组件及其子组件的大小
onLayout() 当该组件需要分配其子组件的位置、大小时
onSizeChange() 当该组件的大小被改变时
onDraw() 当组件将要绘制它的内容时
onKeyDown 当按下某个键盘时
onKeyUp  当松开某个键盘时
onTrackballEvent 当发生轨迹球事件时
onTouchEvent 当发生触屏事件时
onWindowFocusChanged(boolean)  当该组件得到、失去焦点时
onAtrrachedToWindow() 当把该组件放入到某个窗口时
onDetachedFromWindow() 当把该组件从某个窗口上分离时触发的方法
onWindowVisibilityChanged(int): 当包含该组件的窗口的可见性发生改变时触发的方法

源码:点击打开链接:http://download.csdn.net/detail/gangjindianzi/9560849










0 0