自定义View之(包含自定义属性)

自定义View的3种形式:自绘控件(继承View)、组合控件(这个最没意思了)、以及继承控件(继承已经有的控件)


我们想自定义View,只需按照以下几步进行即可:

1)自定义一个View,继承View或者View的子类(如TextView,非ViewGroup)

2)在View的方法中获得我们自定义的属性(如果需要自定义属性的话)

3)重写onMeasure(此方法非必写,大多数情况下还是需要重写的)

4)重写onDraw

注:自定义View只需重写onMeasure和onDraw


1.自定义属性:在res/values下创建attrs文件,声明属性,format中的属性如string代表字符串,color代表颜色等等

 <declare-styleable name="CustomView">
        <attr name="CustomText" format="string"></attr>
        <attr name="CustomTextColor" format="color"></attr>
        <attr name="CustomTextSize" format="dimension"></attr>
 </declare-styleable>


2.在布局文件中引用我们自定义的属性:2.在布局文件中引用我们自定义的属性:

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:cuiboye="http://schemas.android.com/apk/res/com.example.customview"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".MainActivity">

    <com.example.customview.CustomView
        android:id="@+id/tv"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        cuiboye:CustomText="我的"
        cuiboye:CustomTextColor="#ffffff"
        cuiboye:CustomTextSize="16sp" />
</RelativeLayout>

命名空间: xmlns:cuiboye="http://schemas.android.com/apk/res/com.example.customview"


3.自定义View,在构造方法中获得我们自定义的属性:   

public class CustomView extends View {

    private String customText;
    private int customTextSize;
    private int customTextColor;
    private Paint paint;
    private Rect rect;

    public CustomView(Context context) {
        this(context,null);
    }

    public CustomView(Context context, AttributeSet attrs) {
        this(context, attrs,0);
    }

    public CustomView(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        //通过TypedArray获得自定义的属性,AttributeSet中保存的是该View在布局中声明的所有的属性
        //AttributeSet保存的是该View在布局中声明的所有的属性,但是TypedArray不能抛弃,因为TypedArray简化了解析过程(如果布局中的值是包含@+的字符串,解析的值我们看不懂)
        //比如下面的
        //android:layout_height="@dimen/dp200"
        //zhy:text="@string/hello_world"	
        TypedArray typedArray = context.getTheme().obtainStyledAttributes(attrs, R.styleable.CustomView,defStyleAttr,0);//得到自定义的属性
        int indexCount = typedArray.getIndexCount();//此处得到的是自定义属性的数量,不是布局中所有的属性
        for(int i=0;i<indexCount;i++){
            int attr = typedArray.getIndex(i);
            switch (attr){
                case R.styleable.CustomView_CustomText:
                    customText = typedArray.getString(attr);
                    break;
                case R.styleable.CustomView_CustomTextColor:
                    customTextColor = typedArray.getColor(attr, Color.RED);
                    break;
                case R.styleable.CustomView_CustomTextSize:
                    customTextSize = typedArray.getDimensionPixelSize(attr, (int) TypedValue.applyDimension(
                            TypedValue.COMPLEX_UNIT_SP, 16, getResources().getDisplayMetrics()));
                    break;
            }
        }
        typedArray.recycle(); //TypedArray使用完后一定要释放 
        int number = attrs.getAttributeCount();//此处得到的是布局中所有的属性的数量
        //为字画一个矩形
        paint = new Paint();
        paint.setTextSize(customTextSize);
        rect = new Rect();
        paint.getTextBounds(customText,0,customText.length(), rect);
    }

    /**重写onMeasure
     * 测量
     */
    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec)
    {
        int widthMode = MeasureSpec.getMode(widthMeasureSpec);
        int widthSize = MeasureSpec.getSize(widthMeasureSpec);
        int heightMode = MeasureSpec.getMode(heightMeasureSpec);
        int heightSize = MeasureSpec.getSize(heightMeasureSpec);
        int width;
        int height ;
        if (widthMode == MeasureSpec.EXACTLY)
        {
            width = widthSize;
        } else
        {
            paint.setTextSize(customTextSize);
            paint.getTextBounds(customText, 0, customText.length(), rect);
            float textWidth = rect.width();
            int desired = (int) (getPaddingLeft() + textWidth + getPaddingRight());
            width = desired;
        }

        if (heightMode == MeasureSpec.EXACTLY)
        {
            height = heightSize;
        } else
        {
            paint.setTextSize(customTextSize);
            paint.getTextBounds(customText, 0, customText.length(), rect);
            float textHeight = rect.height();
            int desired = (int) (getPaddingTop() + textHeight + getPaddingBottom());
            height = desired;
        }

        setMeasuredDimension(width, height);
    }


    /**重写onDraw
     * 绘制
     */
    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
        paint.setColor(Color.BLUE);
        canvas.drawRect(0,0,getMeasuredWidth(),getMeasuredHeight(),paint);//画一个矩形的画布
        paint.setColor(customTextColor);
        canvas.drawText(customText,getWidth()/2 - rect.width()/2,getHeight()/2 + rect.height()/2,paint);//在画布上画字
    }
}


最后,给出一些容易误解的地方:

如果系统中已经有了语义比较明确的属性(android本身的一些属性),我们也可以直接使用
 1)attrs中这样写           android:text
 2) 布局中这样写      android:text="Hello"
 3)自定义View中这样写     typedArray.getString(R.styleable.CustomView_android_text)





评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值