我套路的自定义View 基础篇 (一)
自定义view 很牛逼,实现起来超级简单!!!跟着我的套路走。
下面代码实现了什么功能也没有的自定义view。重写了onLayout,onMeasure,onSizeChanged。
public class MyView extends View{
private String TAG = "MyView";
public MyView(Context context) {
super(context);
initView();
}
public MyView(Context context, AttributeSet attrs) {
super(context, attrs);
initView();
}
public MyView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
initView();
}
public void initView(){
Log.d(TAG, "onCreat");
}
@Override
protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
Log.d(TAG, "onLayout");
super.onLayout(changed, left, top, right, bottom);
}
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
Log.d(TAG, "onMeasure");
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
}
@Override
protected void onSizeChanged(int w, int h, int oldw, int oldh) {
Log.d(TAG, "onSizeChanged");
super.onSizeChanged(w, h, oldw, oldh);
}
@Override
protected void onDraw(Canvas canvas) {
Log.d(TAG, "onDraw");
super.onDraw(canvas);
}
}
将MyView添加到布局文件中:
<?xml version="1.0" encoding="utf-8"?> <RelativeLayout android:id="@+id/activity_main" xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" android:paddingBottom="@dimen/activity_vertical_margin" android:paddingLeft="@dimen/activity_horizontal_margin" android:paddingRight="@dimen/activity_horizontal_margin" android:paddingTop="@dimen/activity_vertical_margin" tools:context="jaelyn.eventbus.MainActivity"> <jaelyn.eventbus.MyView android:layout_width="wrap_content" android:layout_height="wrap_content" /> </RelativeLayout>
运行后打印的结果为:
在不同的手机运行的打印结果不尽相同,但是大体的顺序是:
onCreat -> onMeasure -> onSizeChange -> onLayout-> onMeasure->onLayout -> onDraw
onCreate
可以在这里面初始化常量如:paint;
也可以获取布局文件中设置的属性。(通过AttributeSet attrs, int defStyleAttr);
onMeasure
计算view的宽高,我们可以在这里根据需要修改view的宽高。
onLayout
view放置的位置。view相对于父控件的位置。如传入的值是(8 ,9 ,100, 100),则view距离父控件的左上角位置(8,9),右下角(100, 100)的范围内显示。(我一般在自定义容器view 的时候会重写这个方法来计算自定义view的子view的位置)。
onSizeChanged
view大小改变的时候会掉用这个方法。我都是用这个方法来获取view的长宽、以及初始化一些位置常量。
onDraw
通过这个方法的canvas,你就可以向屏幕画任何的东西了。
其中对于onMeasure、onLayout 在网上有很多详细的解析,这里就不多讲了。这两个方法比较难理解,你可以先放一放。
去掉这两个方法onMeasure、onLayout,自定义的套路就简化为
1.onCreate(initView):初始化常量
2.onSizeChange:计算位置
3.onDraw: 绘制
接下我们使用这个套路像屏幕写字
public class MyView extends View{
private String TAG = "MyView";
private Paint paint;
float x, y;
private String text = "简单的自定义View";
public MyView(Context context) {
super(context);
initView();
}
public MyView(Context context, AttributeSet attrs) {
super(context, attrs);
initView();
}
public MyView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
initView();
}
public void initView(){
Log.d(TAG, "onCreat");
paint = new Paint();
paint.setColor(Color.RED);
paint.setTextSize(40);
}
@Override
protected void onSizeChanged(int w, int h, int oldw, int oldh) {
Log.d(TAG, "onSizeChanged");
super.onSizeChanged(w, h, oldw, oldh);
Rect bounds = new Rect();
paint.getTextBounds(text, 0, text.length(), bounds);
x = w / 2 - bounds.width() / 2;
y = h / 2 - bounds.height() / 2;
}
@Override
protected void onDraw(Canvas canvas) {
Log.d(TAG, "onDraw");
super.onDraw(canvas);
canvas.drawText("简单的自定义View", x, y , paint);
}
}
效果:
这就是我实现自定义view的基本套路。
在这个基础上可以加入 手机监听、计时器 来实现各种动画效果。