Android学习之自定义view(一)

最近一直在通过看csdn上大牛的博客学自定义view,而且面试中也经常问道怎么自定义view,通过一段时间的学习,算是初步掌握了自定义view的步骤和注意事项,所以特此想总结一下目前阶段所学到的关于自定义view的知识;当然,这也是自定义view的第一篇博客,后续还会有关于自定义view的相关文章。

废话少说,上干货。


自定义view三部曲:

一).在values文件夹下创建attr.xml文件,内容如下:

<declare-styleable name="CustomImageView">  
        <attr name="customimageview" format="reference"/>
</declare-styleable>

这里name一般指定为自定义view的类名,当然也可以是其他任意的字符串,如:test等;然后定义一个属性,这里的属性代表引用一张图片;

format的取值可以为:string,color,demension,integer,enum,reference,float,boolean,fraction,flag,假如属性

定义都为<attr name="attr1" format="xxxtype"/>,那么:

(1) boolean表示布尔值,调用如 xx:attr1="false"
(2) integer表示整型,调用如 xx:attr1="1"
(3) dimension表示尺寸值,调用如 xx:attr1="42dp"
(4) float表示浮点型,调用如 xx:attr1="0.7"
(5) color表示颜色值,调用如 xx:attr1="#00FF00"
(6) string表示字符串,调用如 xx:attr1="#adbddd"
(7) reference表示参考某一资源id,调用如 xx:attr1 = "@drawable/图片ID"

(8) fraction表示百分数,调用如 xx:attr1="30%"

(9)enum:枚举类型

<attr name="ImageScaleType">
            <enum name="fitxy" value="0"/>
            <enum name="center" value="1"/>
</attr>

(10)flag:表示位或运算


<attr name="windowSoftInputMode">
    <flag name = "stateUnspecified" value = "0" />
    <flag name = "stateUnchanged" value = "1" />
    <flag name = "stateHidden" value = "2" />
    <flag name = "stateAlwaysHidden" value = "3" />
    <flag name = "stateVisible" value = "4" />
    <flag name = "stateAlwaysVisible" value = "5" />
    <flag name = "adjustUnspecified" value = "0x00" />
    <flag name = "adjustResize" value = "0x10" />
    <flag name = "adjustPan" value = "0x20" />
    <flag name = "adjustNothing" value = "0x30" />
 </attr> 
调用如:xx:attr1="stateUnspecified | stateUnchanged | stateHidden"

(11) 混合类型,定义为

<declare-styleable name = "combine_type">
    <attr name = "background" format = "reference|color" />
</declare-styleable>

调用如 xx:attr1 = "@drawable/图片ID|#DDFF00"


二)、在布局文件中使用定义的属性,在使用之前,需要引入命名空间:

xmlns:custom="http://schemas.android.com/apk/res/com.example.bottomtabline"

然后就可以使用了,如:

<com.example.bottomtabline.CustomImageView
        android:id="@+id/id1"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:background="#ff0000"
        custom:customimageview="@drawable/ic_action_favor_normal"/>


三)、编写一个类继承自view,然后在构造函数中获取定义的属性

TypedArray ta = context.obtainStyledAttributes(attrs, R.styleable.CustomImageView);
        for(int i=0;i<ta.getIndexCount();i++){
            int attr = ta.getIndex(i);
            switch(attr){
            case R.styleable.CustomImageView_customimageview :
                imageview = BitmapFactory.decodeResource(getResources(), ta.getResourceId(attr,0));
                break;
            }
        }

ta.recycle();

最后就是重写onDraw方法和onMeasure方法

onMeasure方法就是规定组件的大小,它和MeasureSpec有紧密的联系,而MeasureSpec是由两部分组成,分别为模型mode和大小size;

mode的取值最常用的有两种:MeasureSpec.EXACTLY代表布局文件中宽或者高中的match_parent和固定值;

                                                 MeasureSpec.AT_MOST,代表warp_parent;这个时候布局的大小就需要根据实际情况在代码中决定。

最后调用setMeasuredDimension()方法决定组件的大小。只有调用了这个方法之后,getMeasuredWidth()方法才有值,不然就是零。getWidth()(获取组件的大小)和getMeasuredWidth()方法好像一直是相等的,那是因为在onLayout方法中,对这个组件布局的时候,右坐标传入的值就是getMeasuredWidth(),而左坐标为0,两者相减之后还是原来的值,所以它们两个的值是一直相等的。


onDraw方法就是各种直接的画图、画文本的操作

画图片:

protected void onDraw(Canvas canvas) {
        rect.left = 0;
        rect.right = getMeasuredWidth();
        rect.top = 0;
        rect.bottom = getMeasuredHeight();
        canvas.drawBitmap(imageview, null, rect, mPaint);
    }

画半弧:

RectF oval = new RectF(xleft,xtop,xright,xbottom);  //一个矩形

canvas.drawArc(oval, -90, mProgress, false, mPaint);  //画的弧在这个矩形之中  -90代表画弧的起始位置,mProgress代表画的弧有多大

画圆:

drawCircle(float cx, float cy, float radius, Paint paint)  cx、cy代表坐标点,radius代表半径

画文本:

drawText(String text, int start, int end, float x, float y, Paint paint)

画矩形:

drawRect(float left, float top, float right, float bottom, Paint paint)


若现在有一个需求,就是使用多次这个自定义的view的组件,然后让其点击不同的组件来实现不同的业务操作,应该怎么办?这里可以在自定义的view的类里面定义一个接口,然后获取不同组件的id,实现这个接口。

自定义的view类里面:

public void setClickListener(ClickListener l){
        this.listener = l;
    }
    
    public ClickListener getClickListener(){
        return listener;
    }
    
    public interface ClickListener{
        void onClickListener();
    }


在Activity中:

write.setClickListener(new ClickListener() {
            
            @Override
            public void onClickListener() {//在这里面做具体的业务逻辑,比如调转到指定的activity,或者显示提示信息等
                // TODO Auto-generated method stub
                Intent intent = new Intent(MainActivity.this,WriteActivity.class);
                startActivity(intent);
                Toast.makeText(getApplicationContext(), "跳转到编辑界面的Activity", Toast.LENGTH_SHORT).show();
            }
        });
        
        write.setOnClickListener(new View.OnClickListener() {
            
            @Override
            public void onClick(View v) {
                // TODO Auto-generated method stub
                write.getClickListener().onClickListener();
            }
        });


大体自定义view的步骤就这些吧。

很少写博客,阐述的不是很清楚,望见谅,谢谢,最后,附上源码。

源码下载

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值