[关闭]
@guhuizaifeiyang 2018-06-23T03:15:06.000000Z 字数 3278 阅读 1126

自定义View/ViewGroup

Android自定义控件


自定义View系列 谷歌的小弟博客
让你的app提升一个档次-Android酷炫自定义控件
Android 自定义 View 合集 文章合集
自定义控件三部曲之视图篇 启舰的博客
自定义View系列 从零起步,比较系统的自定义View教程。


View

This class represents the basic building block for user interface components. A View occupies a rectangular area on the screen and is responsible for drawing and event handling.

简而言之,View就是屏幕上一块用来和用户进行交互的矩形区域,View需要进行绘制和处理事件。

View的构造函数:

共有4个,具体如下:

  1. 自定义View必须重写至少一个构造函数:
  2. // 如果View是在Java代码里面new的,则调用第一个构造函数
  3. public CarsonView(Context context) {
  4. super(context);
  5. }
  6. // 如果View是在.xml里声明的,则调用第二个构造函数
  7. // 自定义属性是从AttributeSet参数传进来的
  8. public CarsonView(Context context, AttributeSet attrs) {
  9. super(context, attrs);
  10. }
  11. // 不会自动调用
  12. // 一般是在第二个构造函数里主动调用
  13. // 如View有style属性时
  14. public CarsonView(Context context, AttributeSet attrs, int defStyleAttr) {
  15. super(context, attrs, defStyleAttr);
  16. }
  17. //API21之后才使用
  18. // 不会自动调用
  19. // 一般是在第二个构造函数里主动调用
  20. // 如View有style属性时
  21. public CarsonView(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
  22. super(context, attrs, defStyleAttr, defStyleRes);
  23. }

View的坐标系

image_1cg9khtsa1313aou1obh5mo7mm1a.png-61.5kB

MotionEvent中 get 和 getRaw 的区别

  1. event.getX(); //触摸点相对于其所在组件坐标系的坐标
  2. event.getY();
  3. event.getRawX(); //触摸点相对于屏幕默认坐标系的坐标
  4. event.getRawY();

image_1cg9kkmgs1ecd104hne77qf9tu1n.png-44.1kB


getMeasureWidth()和getWidth的区别:

大部分情况二者的值是一样的,但需要注意的是:

获取子控件Margin的方法

如果要自定义ViewGroup支持子控件的layout_margin参数,则自定义的ViewGroup类必须重载generateLayoutParams()函数,并且在该函数中返回一个ViewGroup.MarginLayoutParams派生类对象,这样才能使用margin参数。

实例
效果图
image_1cg6v9v2nmoo2oc81oaoq1ag8t.png-23.8kB

重写generateLayoutParams()函数

  1. @Override
  2. protected LayoutParams generateLayoutParams(LayoutParams p) {
  3. return new MarginLayoutParams(p);
  4. }
  5. @Override
  6. public LayoutParams generateLayoutParams(AttributeSet attrs) {
  7. return new MarginLayoutParams(getContext(), attrs);
  8. }
  9. @Override
  10. protected LayoutParams generateDefaultLayoutParams() {
  11. return new MarginLayoutParams(LayoutParams.MATCH_PARENT,
  12. LayoutParams.MATCH_PARENT);
  13. }

重写onMeasure()

需要将margin也计算进去

  1. protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
  2. super.onMeasure(widthMeasureSpec, heightMeasureSpec);
  3. int measureWidth = MeasureSpec.getSize(widthMeasureSpec);
  4. int measureHeight = MeasureSpec.getSize(heightMeasureSpec);
  5. int measureWidthMode = MeasureSpec.getMode(widthMeasureSpec);
  6. int measureHeightMode = MeasureSpec.getMode(heightMeasureSpec);
  7. int lineWidth = 0;
  8. int lineHeight = 0;
  9. int height = 0;
  10. int width = 0;
  11. int count = getChildCount();
  12. for (int i=0;i<count;i++){
  13. View child = getChildAt(i);
  14. measureChild(child,widthMeasureSpec,heightMeasureSpec);
  15. MarginLayoutParams lp = (MarginLayoutParams) child.getLayoutParams();
  16. int childWidth = child.getMeasuredWidth() + lp.leftMargin +lp.rightMargin;
  17. int childHeight = child.getMeasuredHeight() + lp.topMargin + lp.bottomMargin;
  18. if (lineWidth + childWidth > measureWidth){
  19. //需要换行
  20. width = Math.max(lineWidth,width);
  21. height += lineHeight;
  22. //因为由于盛不下当前控件,而将此控件调到下一行,所以将此控件的高度和宽度初始化给lineHeight、lineWidth
  23. lineHeight = childHeight;
  24. lineWidth = childWidth;
  25. }else{
  26. // 否则累加值lineWidth,lineHeight取最大高度
  27. lineHeight = Math.max(lineHeight,childHeight);
  28. lineWidth += childWidth;
  29. }
  30. //最后一行是不会超出width范围的,所以要单独处理
  31. if (i == count -1){
  32. height += lineHeight;
  33. width = Math.max(width,lineWidth);
  34. }
  35. }
  36. //当属性是MeasureSpec.EXACTLY时,那么它的高度就是确定的,
  37. // 只有当是wrap_content时,根据内部控件的大小来确定它的大小时,大小是不确定的,属性是AT_MOST,此时,就需要我们自己计算它的应当的大小,并设置进去
  38. setMeasuredDimension((measureWidthMode == MeasureSpec.EXACTLY) ? measureWidth
  39. : width, (measureHeightMode == MeasureSpec.EXACTLY) ? measureHeight
  40. : height);
  41. }

重写onLayout()函数

需要将margin加到控件里

添加新批注
在作者公开此批注前,只有你和作者可见。
回复批注