Android之自定义View(一)

自定义View

步骤

在这里插入图片描述

1.1 自定义View属性

res/attrs.xml

<resources>
	<declare-styleable name="TestView">
        <attr name="Title" format="string"/>
        <attr name="TitleColor" format="color"/>
        <attr name="TitleSize" format="dimension"/>
    </declare-styleable>
</resources>
format取值
string:字符串---TypedArray.getString(int)
color:颜色值---TypedArray.getColor(int,int)
dimension:尺寸值,如果是dp就会做像素转换---TypedArray.getDimensionPixelSize(int,int)
integer:整形值---
float:浮点值
fraction:百分数
enum:枚举
boolean:布尔值
flag:自己定义,对应了自己的属性值
reference:指向其他资源---TypedArray.getDimen(int,float)

1.2 引入自定义View

activity_main.xml

使用test:XX对属性进行配置,要记得引入命名空间:xmlns:XX=“http://schemas.android.com/apk/res-auto”

<RelativeLayout xmlns:test="http://schemas.android.com/apk/res-auto">
<com.example.setxfermode.TestView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:background="@color/black"
        test:Title="Zcutie"
        android:padding="10dp"
        test:TitleColor="#ff0000"
        test:TitleSize="30sp"/>
</RelativeLayout>

2.获取自定义View的属性

TestView.java

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

    public TestView(Context context, @Nullable AttributeSet attrs) {
        this(context, attrs,0);
    }
	public TestView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        TypedArray typedArray = context.obtainStyledAttributes(attrs,R.styleable.TestView);
        for(int i =0;i<typedArray.getIndexCount();i++){
            int attr = typedArray.getIndex(i);
            switch (attr){
                case R.styleable.TestView_Title:
                    mTitle = typedArray.getString(i);
                    Log.i(TAG, "title: "+mTitle);
                    break;
                case R.styleable.TestView_TitleColor:
                    mColor = typedArray.getColor(i,Color.BLACK);
                    Log.i(TAG, "title color: "+mColor);
                    break;
                case R.styleable.TestView_TitleSize:
                    mSize = typedArray.getDimensionPixelSize(attr,(int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_SP,16,getResources().getDisplayMetrics()));
                    Log.i(TAG, "title size: "+mSize);
                    break;
                case R.styleable.TestView_viewRef:
                    mRef = typedArray.getDimension(R.styleable.TestView_viewRef,0);
                    Log.i(TAG,"view reference: "+mRef);
                    break;
            }
        }
        typedArray.recycle();
        mPaint = new Paint();
        mBound = new Rect();
        mPaint.setTextSize(mSize);
}

3.重写onMeasure方法

因为在main.xml中引入控件时,设置的值为WRAP_CONTENT,所以会填充整个屏幕,达不到想要的效果,所以,在onMeasure方法中进行处理,即在onMeasure中可以根据自己的需求来设置

onMeasure(int,int)

@Override
protected void onMeasure(int widthMeasureSpec,int heightMeasureSpec){
	//widthMeasureSpec等与在activity_main.xml或者说在引用的xml中进行设置的值有关
	int width = measureWidth(widthMeasureSpec);
	int height = measureHeight(heightMeasureSpec);
	setMeasuredDimension(width,height);
}
measureWidth(int)
//当模式为EXACTLY时,直接赋值defaultWidth
private int measureWidth(int measureSpec){
	int mode = MeasureSpec.getMode(measureSpec);
	int size = MeasureSpec.getSize(measureSpec);
	switch(mode){
		case MeasureSpec.EXACTLY:
			defaultWidth = size;
			break;
		case MeasureSpec.AT_MOST:
			defaultWidth = (int) mPaint.measureText(mTitle)+getPaddingLeft()+getPaddingRight();
			break;
		case MeasureSpec.UNSPECIFIED:
			defaultWidth = Math.max(defaultWidth,size);
			break;
	}
	return defaultWidth;
}
measureHeight(int)
private int measureHeight(int measureSpec){
        int mode = MeasureSpec.getMode(measureSpec);
        int size = MeasureSpec.getSize(measureSpec);
        switch (mode){
            case MeasureSpec.AT_MOST:
                defaultHeight = (int) (-mPaint.ascent()+mPaint.descent()+getPaddingTop()+getPaddingBottom());
                break;
            case MeasureSpec.EXACTLY:
                defaultHeight = size;
                break;
            case MeasureSpec.UNSPECIFIED:
                defaultHeight = Math.max(defaultHeight,size);
                break;
        }
        return defaultHeight;
    }

MeasureSpec

是View的静态内部类,封装了从父级传递到子级的布局要求,每个MeasureSpec代表对宽度或高度的要求,它由大小和模式组成

public static class MeasureSpec{
	private static final int MODE_SHIFT = 30;
	private static final int MODE_MASK = 0x3 << MODE_SHIFT;
	//可能的三种模式:
	//没有约束,子控件想有多大就多大,一般很少使用
    public static final int UNSPECIFIED = 0 << MODE_SHIFT;
    //子控件有设置明确的值或者为MATCH_PARENT
    public static final int EXACTLY = 1 << MODE_SHIFT;
    //子控件能达到最大值,也与父控件相关
    public static final int AT_MOST = 2 << MODE_SHIFT;
    ...
    //获取模式
    public static int getMode(int measureSpec){
        return (measureSpec&MODE_MASK);    
    }
    //获取尺寸
    public static int getSize(int measureSpec){
        return (measureSpec&~MODE_MASK);    
    }
}

4.重写onDraw()

@Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
        Log.i(TAG, "onDraw: ");
        mPaint.setColor(mColor);
        canvas.drawText(mTitle,0,100,mPaint);
        //Log.i(TAG, "onDraw: a half of width is: "+getWidth());
    }

在这里插入图片描述

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值