自定义View

来源:互联网 发布:linux ftp命令 编辑:程序博客网 时间:2024/06/01 07:20



1、创建类继承View 或View的子类
注意:重写构造时,不能缺少两个参数的构造:
否则:报错:
  1. public class MyView extends View{
  2. /**
  3. * 当在布局文件中声明该view,由系统调用此函数创建对象
  4. * @param context
  5. * @param attrs
  6. */
  7. public MyView(Context context, AttributeSet attrs) {
  8. super(context, attrs);
  9. }
  10. /**
  11. * 当在代码中用关键字 new 创建该view时,调用此方法
  12. * @param context
  13. */
  14. public MyView(Context context) {
  15. super(context);
  16. }
2、布局文件中的使用
  1. <zzmyviewz9.view.MyView
  2. android:layout_width="wrap_content"
  3. android:layout_centerInParent="true"
  4. android:layout_height="wrap_content"
  5. />
3、重写相关的方法,实现我们的需求:
一个view 从创建对象,到显示在屏幕上,中间几个重要的步骤:
1、测量大小  
2、指定位置  
3、绘制内容
  1. /**
  2. * 当系统需要测量当前控件大小时,
  3. */
  4. protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
  5. super.onMeasure(widthMeasureSpec, heightMeasureSpec);
  6. // 我们有个任务,就是指定我们自己的大小
  7. // Measured 测量 Dimension 尺寸
  8. setMeasuredDimension(180,100); // 指定我自己宽 180个象素 ,高100个象素
  9. }
  10. /**
  11. * 二: 当系统为view指定位置时,调用此方法 ,对于自定义view 来说,该方法,作用不大
  12. */
  13. protected void onLayout(boolean changed, int left, int top, int right,int bottom) {
  14. super.onLayout(changed, left, top, right, bottom);
  15. }
  16. /**
  17. * 绘制内容
  18. * @param Canvas 画布
  19. */
  20. protected void onDraw(Canvas canvas) {
  21. super.onDraw(canvas);
  22. canvas.drawColor(Color.BLUE); // 绘制一个纯兰色
  23. Paint paint = new Paint(); // 画圆时,所用的画笔
  24. paint.setColor(Color.RED);
  25. canvas.drawCircle(50, 50, 30, paint); // 绘制一个圆,圆心在x轴50象素,Y轴50像素的地方,半径为30象素
  26. }
    onMeasure(int,int);                        // 系统测量控件大小时调用该方法,自己给自己测量宽和高
    onLayout(boolean,int,int,int,int);// 系统为该view 指定位置时调用此方法,子view的位置,自身只有建议权,决定权在父view的手中。传递的参数是距离父控件的左上右下的位置
    onDraw(Canvas);                        // 为本view绘制内容时,调用该方法。       
            // 在主线程中请求重新绘制ondraw方法      invalidate();
     // 在子线程中请求重新绘制ondraw方法     postInvalidate();  
  1. /*
  2. * 自定义控件三部曲
  3. * 1. 重写onMeasure方法
  4. *   用来自己给自己指定一个宽高 系统会给我们推荐一个样式的宽高 但是具体宽高是多少是由我们自己说了算
  5. * 2.重写onLayout方法  
  6.             这个方法 是当我们继承自ViewGroup时复写 当父控件决定了子控件距离它的左上点和右下点之后调用
  7. * 3.重写onDraw方法
  8.             view长什么样 是由自己决定
  9. */
  10. // 觉得自己有多大
  11. @Override
  12. protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
  13. // TODO Auto-generated method stub
  14. super.onMeasure(widthMeasureSpec, widthMeasureSpec);
  15. // 只要复写了这个方法 最好自己给自定指定一个宽高
  16. // 如果自己要给自己指定具体的宽高那么就 setMeasuredDimension 方法
  17. // 如果想通过系统推荐 那么就调用父类的方法
  18. //setMeasuredDimension(200, 100);
  19. }
  20. // 当父控件指定好自己的位置后 告诉我们位置在哪
  21. // 在这里 这个方法的意思不是很大 可以不用理会
  22. // 原因就是因为我们是继承自View的
  23. @Override
  24. protected void onLayout(boolean changed, int left, int top, int right,int bottom) {
  25. // TODO Auto-generated method stub
  26. super.onLayout(changed, left, top, right, bottom);
  27. width = right-left;
  28. height = bottom-top;
  29. }
  30. // 子控件决定自己长什么样子
  31. // 画笔 画布 画布(一张白纸 由我们随便作画)
  32. // 画是一层一层的压上去的
  33. @Override
  34. protected void onDraw(Canvas canvas) {
  35. // 让纸变成红色
  36. canvas.drawColor(Color.RED);
  37. canvas.drawRect(20, 20, 80, 200, paint);
  38. // 指定圆心和半径
  39. canvas.drawCircle(width/2, height/2, width/2, paint);
  40. paint.setColor(Color.YELLOW);
  41. paint.setStyle(Paint.Style.FILL);
  42. // 设置画笔抗锯齿
  43. paint.setAntiAlias(true);
  44. paint.setStrokeWidth(5);
  45. canvas.drawCircle(width/2, height/2, width/2*0.9f, paint);
  46. }

1、onMeasure和onLayout的方法详解

测量的大小:是view 自己想要的大小,在 view.measure 方法执行完以后,就有了
       view.getMeasuredWidth();// 测量的宽
       view.getMeasuredHeight(); //  测量的高
真实的宽和高: view 的真实大小, 是在 view.layout 方法执行完了以后,才会有的值
       view.getWidth(); // 真实的宽
       view.getHeight(); // 真实的高
  1. @Override
  2. /**
  3. * 当系统需要测量控件大小的时候,调用此方法,
  4. * 如果是一个view 那么,指定自己的大小就可以了,
  5. * 如果是一个布局(例如ViewGroup),不但要指定自己的大小,同时还要测量所有的子view 的大小。
  6. * 参数一: widthMeasureSpec 宽度的大小和建议
  7. * 参数一: heightMeasureSpec 高度的大小和建议
  8. */
  9. protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
  10. super.onMeasure(widthMeasureSpec, heightMeasureSpec);
  11. // 模式和size 模式是int类型的前两位 size是后 30位
  12. // int sizeWidth = MeasureSpec.getSize(widthMeasureSpec); // 获得宽度尺寸
  13. // int modeWidth = MeasureSpec.getMode(widthMeasureSpec); // 获得宽度的相应模式
  14. /*
  15. * 先测量谁(父控件还是子view),测量多少次都是不确定的
  16. */
  17. //可以指定
  18. //MeasureSpec.makeMeasureSpec(size, mode)
  19. // 测量所有的子view的大小
  20. for(int i=0;i<getChildCount();i++){
  21. View view = getChildAt(i);
  22. view.measure(widthMeasureSpec, heightMeasureSpec);
  23. /*
  24. * 测量的大小:是view 自己想要的大小,在 view.measure 方法执行完以后,就有了
  25. * view.getMeasuredWidth();// 测量的宽
  26. view.getMeasuredHeight(); // 测量的高
  27. */
  28. }
  29. //缺少这句话,则会导致没有测量位置:导致linearlayout显示,但是他的自view没有显示
  30. //更好的方法是:使用for循环,给每一子view指定位置
  31. //getChildAt(2).measure(widthMeasureSpec, heightMeasureSpec);
  32. }
  33. @Override
  34. /**
  35. * 当父view为当前控件指定位置后,调用此方法 ,做为一个viewGroup,必须在此方法中,为子view指定位置
  36. * @param changed 当前控件的大小,位置,是否发生改变
  37. * @param l t r b 当前控件在父view坐标系中的位置
  38. *
  39. */
  40. protected void onLayout(boolean changed, int l, int t, int r, int b) {
  41. //System.out.println("ltrb:"+ l+" : "+t +" : "+r +" : "+b);
  42. // 一个viewGroup在onlayout 中的任务就是为,子view 指定位置
  43. //View child0 = getChildAt(0);
  44. //child0.layout(0, 0, getWidth(), getHeight()); // 四个参数,分别是 child0 在当前view中的位置
  45. //View child1 = getChildAt(1);
  46. //child1.layout(getWidth(), 0, getWidth()*2, getHeight()); // 四个参数,分别是 child0 在当前view中的位置
  47. for(int i=0;i<getChildCount();i++){
  48. View view = getChildAt(i);
  49. // 让第一个子view填充满整个viewGroup,以后的子view,依次向右移动一个宽度
  50. view.layout(0+i*getWidth(), 0, getWidth()+i*getWidth(), getHeight());
  51. // view 的真实大小, 是在 view.layout 方法执行完了以后,才会有的值
  52. //view.getWidth(); // 真实的宽
  53. //view.getHeight(); // 真实的高
  54. }
  55. }
注意:

  1. @Override
  2. // 系统测量控件大小时,调用
  3. protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
  4. super.onMeasure(widthMeasureSpec, heightMeasureSpec);
  5. //getMeasuredHeight(); //
  6. }
  7. @Override
  8. // 当父view为我们指定好位置后,调用此方法,告诉我们的位置
  9. protected void onLayout(boolean changed, int left, int top, int right,
  10. int bottom) {
  11. super.onLayout(changed, left, top, right, bottom);
  12. // 真实的高度,只有当 onLayout 执行了以后才能获得
  13. this.top = getHeight();
  14. System.out.println(top);
  15. }

0 0