Android自定义控件

来源:互联网 发布:手机淘宝联盟自己购买 编辑:程序博客网 时间:2024/05/01 16:38

转载自
http://www.cnblogs.com/0616–ataozhijia/p/4003380.html
http://blog.163.com/ppy2790@126/blog/static/103242241201382210910473/
开发自定义控件的步骤:
1、了解View的工作原理
2、 编写继承自View的子类
3、 为自定义View类增加属性
4、 绘制控件
5、 响应用户消息
6 、自定义回调函数
一、View结构原理
Android系统的视图结构的设计也采用了组合模式,即View作为所有图形的基类,Viewgroup对View继承扩展为视图容器类。
View定义了绘图的基本操作
基本操作由三个函数完成:measure()、layout()、draw(),其内部又分别包含了onMeasure()、onLayout()、onDraw()三个子方法。具体操作如下:
1、measure操作
measure操作主要用于计算视图的大小,即视图的宽度和长度。在view中定义为final类型,要求子类不能修改。measure()函数中又会调用下面的函数:
(1)onMeasure(),视图大小的将在这里最终确定,也就是说measure只是对onMeasure的一个包装,子类可以覆写onMeasure()方法实现自己的计算视图大小的方式,并通过setMeasuredDimension(width, height)保存计算结果。
2、layout操作
layout操作用于设置视图在屏幕中显示的位置。在view中定义为final类型,要求子类不能修改。layout()函数中有两个基本操作:
(1)setFrame(l,t,r,b),l,t,r,b即子视图在父视图中的具体位置,该函数用于将这些参数保存起来;
(2)onLayout(),在View中这个函数什么都不会做,提供该函数主要是为viewGroup类型布局子视图用的;
3、draw操作
draw操作利用前两部得到的参数,将视图显示在屏幕上,到这里也就完成了整个的视图绘制工作。子类也不应该修改该方法,因为其内部定义了绘图的基本操作:
(1)绘制背景;
(2)如果要视图显示渐变框,这里会做一些准备工作;
(3)绘制视图本身,即调用onDraw()函数。在view中onDraw()是个空函数,也就是说具体的视图都要覆写该函数来实现自己的显示(比如TextView在这里实现了绘制文字的过程)。而对于ViewGroup则不需要实现该函数,因为作为容器是“没有内容“的,其包含了多个子view,而子View已经实现了自己的绘制方法,因此只需要告诉子view绘制自己就可以了,也就是下面的dispatchDraw()方法;
(4)绘制子视图,即dispatchDraw()函数。在view中这是个空函数,具体的视图不需要实现该方法,它是专门为容器类准备的,也就是容器类必须实现该方法;
(5)如果需要(应用程序调用了setVerticalFadingEdge或者setHorizontalFadingEdge),开始绘制渐变框;
(6)绘制滚动条;
从上面可以看出自定义View需要最少覆写onMeasure()和onDraw()两个方法。
二、View类的构造方法
创建自定义控件的3种主要实现方式:
1)继承已有的控件来实现自定义控件: 主要是当要实现的控件和已有的控件在很多方面比较类似, 通过对已有控件的扩展来满足要求。
2)通过继承一个布局文件实现自定义控件,一般来说做组合控件时可以通过这个方式来实现。
注意此时不用onDraw方法,在构造广告中通过inflater加载自定义控件的布局文件,再addView(view),自定义控件的图形界面就加载进来了。
3)通过继承view类来实现自定义控件,使用GDI绘制出组件界面,一般无法通过上述两种方式来实现时用该方式。
View(Context context)
Simple constructor to use when creating a view from code.
View(Context context, AttributeSet attrs)
Constructor that is called when inflating a view from XML.
View(Context context, AttributeSet attrs, int defStyle)
Perform inflation from XML and apply a class-specific base style.
三、自定义View增加属性的两种方法:
1)在View类中定义。通过构造函数中引入的AttributeSet 去查找XML布局的属性名称,然后找到它对应引用的资源ID去找值。
案例:实现一个带文字的图片(图片、文字是onDraw方法重绘实现)

public class MyView extends View {    private String mtext;    private int msrc;    public MyView(Context context) {        super(context);        // TODO Auto-generated constructor stub    }    public MyView(Context context, AttributeSet attrs) {        super(context, attrs);        // TODO Auto-generated constructor stub        int resourceId = 0;        int textId = attrs.getAttributeResourceValue(null, "Text",0);        int srcId = attrs.getAttributeResourceValue(null, "Src", 0);        mtext = context.getResources().getText(textId).toString();        msrc = srcId;    }    @Override    protected void onDraw(Canvas canvas) {        // TODO Auto-generated method stub        Paint paint = new Paint();        paint.setColor(Color.RED);        InputStream is = getResources().openRawResource(msrc);             Bitmap mBitmap = BitmapFactory.decodeStream(is);            int bh = mBitmap.getHeight();            int bw = mBitmap.getWidth();        canvas.drawBitmap(mBitmap, 0,0, paint);        //canvas.drawCircle(40, 90, 15, paint);        canvas.drawText(mtext, bw/2, 30, 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>

属性Text, Src在自定义View类的构造方法中读取。
2)通过XML为View注册属性。与Android提供的标准属性写法一样。
案例: 实现一个带文字说明的ImageView (ImageView+TextView组合,文字说明,可在布局文件中设置位置)

public class MyImageView extends LinearLayout {    public MyImageView(Context context) {        super(context);        // TODO Auto-generated constructor stub    }    public MyImageView(Context context, AttributeSet attrs) {        super(context, attrs);        // TODO Auto-generated constructor stub        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”
然后可以像使用系统的属性一样使用: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>

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

0 0
原创粉丝点击
热门问题 老师的惩罚 人脸识别 我在镇武司摸鱼那些年 重生之率土为王 我在大康的咸鱼生活 盘龙之生命进化 天生仙种 凡人之先天五行 春回大明朝 姑娘不必设防,我是瞎子 快手号手机丢了怎么办 手机号码不停收到验证码怎么办 手机网页滑动自动跳到最下面怎么办 网页一打开就跳至评论怎么办? 百度总出现重复的网页怎么办 苹果7一直处于系统升级页面怎么办 手机看百度文章总是跳转怎么办 美度舵手滑丝怎么办 小区房产证办不下来怎么办 美海军陆战队进驻台湾大陆怎么办? 束脚裤带子怎么办系 眼角弄伤了应该怎么办 浴盆下水盖坏了怎么办 冒险岛勋章多了怎么办 玉手镯取不下来怎么办?终极绝招! 陆金所收益低怎么办 陆金所登录密码忘记怎么办 陆金所理财逾期怎么办 死亡家属晚上来闹怎么办 开车撞到人家属闹要请护工怎么办 骑马与砍杀战团打下城市怎么办 我的脑子有问题怎么办 公司外派异地工作医保怎么办 老鼠死在墙里面怎么办 父亲再婚婚后对我不好怎么办 皮衣搽了护理油后不亮了怎么办 新买的衣服皱了怎么办 新买的裙子很皱怎么办 新买的风衣很皱怎么办 新买的裙子皱了怎么办 货拉拉准点率低怎么办 定机票名字打错了怎么办 做坏事被发现了怎么办 在阳台做被发现怎么办 有秘密被发现了怎么办 微店没有收到货怎么办 cf与主机连接不稳定怎么办 穿越火线与主机连接不稳定怎么办 word被锁定无法编辑怎么办 平衡车系统乱了怎么办 监控老是滴滴的响怎么办