自定义组件的简单使用—View
1、 控件是怎么来的?
每一个控件都是使用绘图的方式绘制出来的
2、开发自定义组件的几种方法
A、从0开始开发自定义组件,从View或ViewGroup类继承,难度最大
B、从已有组件继承,比如定义ImageView、ListView继承,为已有组件添加新的功能
C、将多个已有的组件组合成一个新的组件
3、View类
A、构造方法
public MyView(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
}
如果给组件定义了样式和主题,则会调用该方法。
public MyView(Context context, AttributeSet attrs) {
super(context, attrs);
}
在layout文件中使用组件,则调用该方法。会自动将组件的属性传递给attrs参数,从该参数中可以获取定义在xml的属性。
<com.trkj.dept12_customer1.MyView
android:layout_width="wrap_content"
android:layout_height="wrap_content" />
public MyView(Context context) {
super(context);
}
直接代码创建组件,一般会调用该方法,所以属性都使用默认值
Button btn = new Button(this);
B、onDraw()方法
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
}
用于组件的绘制
C、onMeasure()方法
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
}
该方法用于确定组件的大小
A、参数:
widthMeasureSpec:保存了宽度的模式(match_parent、wrap_content、具体值)和大小
heightMeasureSpec:保存了高度的模式(match_parent、wrap_content、具体值)和大小
绝大部分情况下,我们只需要计算wrap_content(跟随内容)的情况
B、关于测量模式,一共有三种:
MeasureSpec.AT_MOST:是最大尺寸,当控件的layout_width或layout_height指定为WRAP_CONTENT时,控件大小一般随着控件的子空间或内容进行变化,此时控件尺寸只要不超过父控件允许的最大尺寸即可。该模式必须要通过编程计算。
MeasureSpec.EXACTLY:是精确尺寸,当我们将控件的layout_width或layout_height指定为具体数值时如andorid:layout_width="50dip",或者为match_parent是,都是控件大小已经确定的情况,都是精确尺寸。
MeasureSpec.UNSPECIFIED:是未指定尺寸,这种情况不多,一般都是父控件是AdapterView,通过measure方法传入的模式。
C、如何获取组件的测量模式和大小?
//获取宽度使用的模式
int wmode = MeasureSpec.getMode(widthMeasureSpec);
//获取宽度大小
int wsize = MeasureSpec.getSize(widthMeasureSpec);
//获取高度使用的模式
int hmode = MeasureSpec.getMode(heightMeasureSpec);
//获取高度大小
int hsize = MeasureSpec.getSize(heightMeasureSpec);
D、测量出组件的宽度和高度之后,如果应用该大小?
//下面的方法一定要调用,用于应用计算出来的宽度和高度
setMeasuredDimension(wsize, hsize);
E、onMeasure()的完整写法:
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
//获取宽度使用的模式
int wmode = MeasureSpec.getMode(widthMeasureSpec);
//获取宽度大小
int wsize = MeasureSpec.getSize(widthMeasureSpec);
//组件的实际宽度
int width = 0;
if(wmode == MeasureSpec.AT_MOST){
//计算宽度
}else{
//wsize就是父容器的大小,在EXACTLY模式下,父窗口的大小的组件的大小
width = wsize;
}
//获取高度使用的模式
int hmode = MeasureSpec.getMode(heightMeasureSpec);
//获取高度大小
int hsize = MeasureSpec.getSize(heightMeasureSpec);
int height = 0;
if(hmode == MeasureSpec.AT_MOST){
//计算高度
}else{
height = hsize;
}
//下面的方法一定要调用,用于应用计算出来的宽度和高度
setMeasuredDimension(width, height);
}
4、案例:模拟TextView,角为圆角
/**
* qq:2286502415
* @time:2016-1-16
* @author Administrator
*
*/
public class MyView extends View {
private String text = "中华文艺复兴";
private Paint paint;
public MyView(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
}
public MyView(Context context, AttributeSet attrs) {
super(context, attrs);
paint = new Paint();
paint.setAntiAlias(true);
paint.setColor(Color.WHITE);
paint.setTextSize(40);
}
public MyView(Context context) {
super(context);
}
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
int width = getMeasuredWidth();
int height = getMeasuredHeight();
Log.e("tag: ", "onDraw");
// 画填充的圆角矩形
Paint p = new Paint();
p.setColor(Color.RED);
canvas.drawRoundRect(new RectF(1, 1, width - 1, height - 1), 15, 15, p);
// 画文字
// 计算出文字所占的大小
Rect bounds = new Rect();
paint.getTextBounds(text, 0, text.length(), bounds);//从第一个到最后一个文字的距离
int left = (width - bounds.width()) / 2;//居中
int top = (height - bounds.height()) / 2;
Log.i("MyView", "top:" + top);
Log.i("MyView", "height:" + bounds.height());
canvas.drawText(text, left, top + bounds.height(), paint);
//各参数意义(文本,字符串的左边在屏幕的位置,字符串下边线距离屏幕顶端的距离,画笔。参考:http://blog.csdn.net/sirnuo/article/details/21165665)
}
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
// 计算出文字所占的大小
Rect bounds = new Rect();
paint.getTextBounds(text, 0, text.length(), bounds);
Log.e("tag: ", "onMeasure");
// 获取宽度使用的模式
int wmode = MeasureSpec.getMode(widthMeasureSpec);
// 获取宽度大小
int wsize = MeasureSpec.getSize(widthMeasureSpec);
// 组件的实际宽度
int width = 0;
if (wmode == MeasureSpec.AT_MOST) {
// 计算宽度
width = bounds.width();
} else {
// wsize就是父容器的大小,在EXACTLY模式下,父窗口的大小的组件的大小
width = wsize;
}
// 获取高度使用的模式
int hmode = MeasureSpec.getMode(heightMeasureSpec);
// 获取高度大小
int hsize = MeasureSpec.getSize(heightMeasureSpec);
int height = 0;
if (hmode == MeasureSpec.AT_MOST) {
// 计算高度
height = bounds.height();
} else {
height = hsize;
}
// 下面的方法一定要调用,用于应用计算出来的宽度和高度
setMeasuredDimension(width, height);
}
}
效果图: