在安卓开发过程中会经常需要用到这种自定义控件 今天,从最简单的自定义控件开始写起:
实现步骤:
1.创建一个类,继承View或者viewGroup
区别:自定义的View就是一个单一的控件,里边不能放别的控件,例如Textview,Button等,只能显示一些效果,但不会像Linealayout那样能存放控件
自定义的ViewGroup就相当于一个容器,能存放其他控件,我们创建的布局文件中的根布局默认是RelativeLayout或者是LineaLayout
什么是容器呢?说简单点,LineaLayout里边可以放多个TextView或者Button等控件,但是Button或者TextView中是不能放Button的
2.写构造方法
构造方法目前最多好像有四个,这里我只说前三个
第一个 这个构造方法一般是在代码中动态的添加自定义View时用的
public MyView(Context context) {
super(context);
}
第二个 这个构造方法是一般是我们在布局文件中使用的自定义view,由系统去掉的 第二个参数为参数集合 布局文件设置的宽度.高度
边距等属性,都放到这个参数集合中.
public MyView(Context context, AttributeSet attrs) {
super(context, attrs);
}
第三个 defStyle表示设置的风格 少用 public MyView(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
}
注意 因为我们自定义的View一般需要在构造函数中初始化一些设置,所以我将里边的构造方法改变如下: public MyView(Context context) {
this(context,null);
}
public MyView(Context context, AttributeSet attrs) {
this(context, attrs,0);
}
public MyView(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
//在这里进行一些初始化操作
}
3.初始化操作 我们需要创建一个画笔,并将其提升为一个成员变量,再给咱们的画笔添加一个颜色 Paint mPaint = new Paint();
mPaint.setColor(Color.RED);
接着我们再创建一个矩形并设置它的宽和高,也把他提成一个成员变量 mRect = new Rect(0, 0, 50, 60);
4.这个时候我们就可以用刚才创建的画笔来画我们想要的东西 我们需要重写onDraw方法 这个方法是专门来画控件的
.在view的创建过程中会多次调用这个方法来画view
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
canvas.drawRect(mRect, mPaint);
}
注意 :为什么要在构造方法中创建画笔而不在这里创建就是因为这个方法或不断的调用 如果我们在这里创建的话就会不断创建画笔,
导致资源浪费
5.下边我们开始使用这个自定义view
先copy全类名 选中刚才创建的这个自定义view的类名,然后根据下图所示复制全类名
注意 自定义控件在布局文件中使用必须copy全类名
6.在布局文件中使用
<com.example.defindedview.MyView
android:layout_width="wrap_content"
android:layout_height="wrap_content" />
7.运行,看效果图
模拟其上的效果突出来了, 看上去没有什么问题吧,表面上看是没有什么问题,但是我说有问题,什么问题呢
我在布局文件中给这个自定义控件添加一个背景颜色android:background="#999",后再看效果图
看到了吧,我刚才宽度写的是wrap_content,为什么不是自适应,而是填满父view了
原因如下
android:layout_width的值有三种
1.wrap_content 自适应控件的大小
2.match_parent和fill_parent 填充满父窗口
3.30dp 30px等 确定大小
我们设置的是wrap_content ,也就是自适应布局大小,系统怎么知道我们的控件大小有多大呢?系统
确定控件大小是通过onMeasure这个方法去测量控件的大小的,那么我们没有重写这个方法,系统就
会默认去掉自定义控件View中的onMeasure,而View中的onMeasure测量结果默认是填满父view,
所以我们的自定义view就显示了全屏的效果
8.下边我们去测量我们的控件大小,来解决这个问题
我们需要重写onMeasure方法
/**
* 我们分别获取宽和高的模式和默认测量大小 模式有三种 UNSPECIFIED 不常用 AT_MOST
* 根据字面意思最多,它对应的是wrap_content EXACTLY
* 确定大小,对应的是match_parent和fill_parent或者30dp 30px等确定大小
*/
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
int widthMode = MeasureSpec.getMode(widthMeasureSpec);
int width = MeasureSpec.getSize(widthMeasureSpec);
int heightMode = MeasureSpec.getMode(widthMeasureSpec);
int height = MeasureSpec.getSize(widthMeasureSpec);
if (widthMode == MeasureSpec.EXACTLY) {// 如果是确定大小 我们就测量的真实大小等于默认测量大小
measureWidth = width;
} else {// 如果不是确定大小 就需要自己去测量了 我们的自定义view中只用一个矩形
// 那就根据这个矩形来测量 矩形的宽度加上内边距
measureWidth = mRect.width() + getPaddingLeft() + getPaddingRight();
}
if (heightMode == MeasureSpec.EXACTLY) {
measureHeight = height;
} else {
measureHeight = mRect.height() + getPaddingTop()
+ getPaddingBottom();
}
setMeasuredDimension(measureWidth, measureHeight);//最后我们将我们测量的高度设置上去
}
9.再次运行一下
你会发现 刚才的背景已经没有了 是自适应屏幕的
到这里基本最基本的自定义的控件你已经明白具体步骤了
来总结一下步骤
1.创建一个类,继承View或者ViewGroup
2.添加构造方法,并在构造方法中进行初始化
3.重写onMeasure方法,测量控件的大小(非必须)
4.重写onDraw方法,画自定义控件
点击这里获取源码