源码地址:https://github.com/ldy1993/ToolforAS.git
我这里很简单学习自定义view,可以借助百度和android,api弄懂别人写什么即可。
************************************************************************************************************************
深入的话可以看下面链接,我觉得他写的好好,有时间我也自己写一份关于view的专栏。
https://blog.csdn.net/lfdfhl/article/details/51671038
*********************************************************************************************************************************
首先创建一个SuspensionView类,继承View
有时我们会发现as的android.view.View不能自动导入,那是因为setting中自动导包做了限制,本来取消就可以,但是我觉得他既然在那里默认设置了,应该是有用的。所以我没有去掉,手动去import android.view.View;
然后使用快捷键alt+insert实现构造方法,各种有参和无参构造方法,我们先不理参数的具体意义,我们后面在讲。先看自定义View的三个重要的步骤:measure,layout,draw。我们分别重写上述方法
onMeasure
首先分析measure测量,onMeasure主要的工作是测量子view的本身的大小,如下
onMeasure可以自动解析xml,或者在重写onMeasure使用java,例如setMeasuredDimension(width, height);
重新定义测量view的大小,如下
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
setMeasuredDimension(100, 22);
}
其中widthMeasureSpec和heightMeasureSpec属于MeasureSpec,他是一种MeasureSpec通常翻译为”测量规格”,它是一个32位的int数据. 其中高2位代表SpecMode即某种测量模式,低30位为SpecSize代表在该模式下的规格大小.
1 MeasureSpec封装了父布局传递给子View的布局要求。
2 MeasureSpec可以表示宽和高
3 MeasureSpec由size和mode组成
可以通过如下方式分别获取这两个值:
获取SpecSize
int specSize = MeasureSpec.getSize(measureSpec)
获取specMode
int specMode = MeasureSpec.getMode(measureSpec)
当然,也可以通过这两个值生成新的MeasureSpec
int measureSpec=MeasureSpec.makeMeasureSpec(size, mode);
SpecMode一共有三种:
MeasureSpec.EXACTLY
官方文档的描述:The parent has determined an exact size for the child. The child is going to be given those bounds regardless of how big it wants to be.
MeasureSpec.EXACTLY模式表示:父容器已经检测出子View所需要的精确大小。 在该模式下,View的测量大小即SpecSize。
MeasureSpec.AT_MOST
官方文档的描述:The child can be as large as it wants up to the specified size.
MeasureSpec.AT_MOST模式表示:父容器未能检测出子View所需要的精确大小,但是指定了一个可用大小即specSize
在该模式下,View的测量大小不能超过SpecSize。
MeasureSpec.UNSPECIFIED
官方文档的描述:The parent has not imposed any constraint on the child. It can be whatever size it wants.
父容器不对子View的大小做限制.
MeasureSpec.UNSPECIFIED这种模式一般用作Android系统内部,或者ListView和ScrollView等滑动控件,
SpecSize即为控件的大小。
重新onMeasure我们可以获取宽高的MeasureSpec,然后对控件本身大小重新做修改,通常可以用于控件不断重绘制过程不断改变其大小。或者为绘制或者布局提供长宽的数据参考。
onLayout
onLayout()方法用于确定子View的位置,重写onLayout()方法,我们可以重新确认子View的位置
onLayout有五个参数,l,t是代表一个子view左上角的点,r,b是代表右下角的点。change代表该子view是否改变位置。
@Override
protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
Log.e(TAG, "onLayout: " +left+";;"+top+";;"+right+";;"+bottom);
super.onLayout(changed, left, top, right, bottom);
}
layout()方法用于View确定自己本身在其父View的位置 ,调用了这个方法后会自动回调onLayout
onDraw
ondraw用于在子View绘制图案。
canvas,画布,在上面调用drawCircle或者line去画圆或者画线。还有很多形状可以在用时面向搜索引擎编程。
mpaint,画笔,可以决定画出来的颜色和画笔类型。
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
mpaint.setColor(Color.RED);
mpaint.setStyle(Paint.Style.FILL_AND_STROKE);
// canvas.drawLine(10,100,10,100,mpaint);
canvas.drawCircle(l,t,20,mpaint);
cv=canvas;
}
以一个跟随小球为例。在onTouch中去获取触摸点的坐标,然后更新ui,回调onDraw,于是重新改变小球位置
@Override
public boolean onTouchEvent(MotionEvent event) {
Log.e(TAG, "event: " +event.getX()+";;"+event.getY());
Log.e(TAG, "event: " +event.getX()+";;"+event.getY());
l=(int)event.getX();
t=(int)event.getY();
//更新ui
invalidate();
return true;
}
下一节
3.5、创建listview并通过Adapter注入数据