java android 控件_Android 自定义控件(一)

在开发过程中经常遇到自定义控件,打算自己一边写着博客一边总结一下自定义View 的过程,以便能更好的提高。

新建一个自定义View,继承View,实现父类的构造方法.

public classMyFirstView extendsView {

publicMyFirstView(Context context) {

this(context,null);

}

publicMyFirstView(Context context, AttributeSet attrs) {

this(context,attrs,0);

}

publicMyFirstView(Context context, AttributeSet attrs, intdefStyleAttr) {

super(context, attrs, defStyleAttr);

}

}

注意更改直接引用的构造方法,以下是三个构造函数使用时机。

①.在代码中直接new一个MyFirstView实例的时候,会调用第一个构造函数.这个没有任何争议.

②.在xml布局文件中调用MyFirstView的时候,会调用第二个构造函数.这个也没有争议.

③.在xml布局文件中调用MyFirstView,并且MyFirstView标签中还有自定义属性时,这里调用的还是第二个构造函数.

也就是说,系统默认只会调用Custom View的前两个构造函数,至于第三个构造函数的调用,通常是我们自己在构造函数中主动调用的(例如,在第二个构造函数中调用第三个构造函数).

自定义View的属性,首先在res/values/  下找到attrs.xml (如果没有可以创建一个), 在里面定义我们的属性和声明我们的整个样式。

然后就是定义属性值了,通过 方式定义属性值,属性名字同样也要起的见名知意,format表示这个属性的值的类型,类型有以下几种:

reference:引用资源        string:字符串        Color:颜色         boolean:布尔值         dimension:尺寸值        float:浮点型        integer:整型      fraction:百分数             enum:枚举类型            flag:位或运算

然后在布局中声明我们的自定义View

其中 xmlns:first="http://schemas.android.com/apk/res-auto" 是引入自己的命名空间,也可以写成xmlns:first="http://schemas.android.com/apk/res/com.shsany.practice"的命名空间,后面的包路径指的是项目的package。

在上面的第三个构造方法里获取MyFirstView 的属性。

publicMyFirstView(Context context, AttributeSet attrs, intdefStyleAttr) {

super(context, attrs, defStyleAttr);

TypedArray typedArray = context.getTheme().obtainStyledAttributes(attrs, R.styleable.MyFirstView, defStyleAttr, 0);

if(typedArray != null) {

mText= typedArray.getString(R.styleable.MyFirstView_text);

mTextColor= typedArray.getColor(R.styleable.MyFirstView_textColor, Color.RED);

//默认设置为16sp,intx = typedArray.getDimensionPixelSize(R.styleable.MyFirstView_textSize, 16);

mTextSize= DisplayUtil.sptopx(context, (float) x);

}

typedArray.recycle();

/**绘制文本的宽长*/mPaint= newPaint();

mPaint.setTextSize(mTextSize);

mBound= newRect();

mPaint.getTextBounds(mText, 0, mText.length(), mBound);

}

然后再重写onDraw()方法绘制控件。

@Overrideprotected voidonDraw(Canvas canvas) {

super.onDraw(canvas);

if(mPaint!= null) {

/**设置圆形的颜色为红色*/mPaint.setColor(Color.RED);

canvas.drawCircle(getWidth()/2f, getWidth()/2f, getWidth()/2f, mPaint);

/**设置文本的颜色 及 位置 这里的x y值是文本左下角点的x y值*/mPaint.setColor(mTextColor);

canvas.drawText(mText, getWidth() / 2- mBound.width() / 2, getHeight() / 2+ mBound.height() / 2, mPaint);

}

}

此时的效果是

a6633e1d662ceac058cb22d3cb69553c.png

系统帮我们测量的高度和宽度都是MATCH_PARNET,当我们设置明确的宽度和高度时,系统帮我们测量的结果就是我们设置的结果,当我们设置为WRAP_CONTENT,或者MATCH_PARENT系统帮我们测量的结果就是MATCH_PARENT的长度。所以,当设置了WRAP_CONTENT时,我们需要自己进行测量,即重写onMesure()方法,

重写之前先了解MeasureSpec的specMode,一共三种类型:

EXACTLY:一般是设置了明确的值或者是MATCH_PARENT

AT_MOST:表示子布局限制在一个最大值内,一般为WARP_CONTENT

UNSPECIFIED:表示子布局想要多大就多大,很少使用

下面是我们重写onMeasure代码:

@Overrideprotected voidonMeasure(intwidthMeasureSpec, intheightMeasureSpec) {

intwidthMode = MeasureSpec.getMode(widthMeasureSpec);

intwidthSize = MeasureSpec.getSize(widthMeasureSpec);

intheightMode = MeasureSpec.getMode(heightMeasureSpec);

intheightSize = MeasureSpec.getSize(heightMeasureSpec);

intwidth;

intheight;

if(widthMode == MeasureSpec.EXACTLY) {

/**如果规定了具体的数值直接等于*/width = widthSize;

} else{

/**如果没规定具体的数值,就根据当前文字的宽度加上内边距 就是这个控件的宽度*/floattextWidth = mBound.width();

intdesired = (int) (getPaddingLeft() + textWidth + getPaddingRight());

width = desired;

}

if(heightMode == MeasureSpec.EXACTLY) {

/**如果规定了具体的数值直接等于*/height = heightSize;

} else{

/**如果没规定具体的数值,就根据当前文字的高度加上内边距 就是这个控件的高度*/floattextHeight = mBound.height();

intdesired = (int) (getPaddingTop() + textHeight + getPaddingBottom());

height = desired;

}

/**判断宽高那个大 那个大听那个*/if(width>height){

height=width;

}else{

width=height;

}

/***最后调用父类方法,把View的大小告诉父布局。*/setMeasuredDimension(width, height);

}

此时运行的结果是

14a77195a51ed4dbdeaa1ed8265564c9.png

这样,我们的第一个控件已经实现了,下面我们来总结一下自定义View 的步骤:

1.先自定义一个view,重写其构造方法。

2.自定义view 的属性,在垢找方法

3.重写onMeasure(int,int)方法。(该方法可重写可不重写,具体看需求)

4.重写onDraw(Canvas canvas)方法。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值