相关文章:

Android 知识点总结(目录) https://blog.csdn.net/a136447572/article/details/81027701

view绘制主要包括三个方面:

measure 测量组件本身的大小
layout 确定组件在视图中的位置
draw 根据位置和大小,将组件画出来

measure
绘制组件的大小

 @Override    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {        super.onMeasure(widthMeasureSpec, heightMeasureSpec);   }

重写onMeasure 是 会有两个参数 widthMeasureSpec与heightMeasureSpec 这连个参数是系统提供的控件高度的建议值但最终值需要通过setMeasuredDimension() 方法来设置

        int widthMeasure = MeasureSpec.getSize(widthMeasureSpec);        int widthMeasureMode = MeasureSpec.getMode(widthMeasureSpec);        int heightMeasure = MeasureSpec.getSize(heightMeasureSpec);        int heightMeasureMode = MeasureSpec.getMode(heightMeasureSpec);

widthMeasureSpec与heightMeasureSpec 值 都是一个组合尺寸,它是一个32位bit值,高两位是尺寸模式specMode,低30位是尺寸大小值

可以通过 MeasureSpec.getSize() 与 MeasureSpec.getMode()方法分别获取尺寸模式和具体值

MeasureSpec.EXACTLY    用户指定 match_parent 或大小 :layout_width="50dip"MeasureSpec.AT_MOST    用户指定 android:layout_width="wrap_content"MeasureSpec.UNSPECIFIED  是用户未指定尺寸,这种情况不多

在 ViewGroup中 需要通过 measureChildren(widthMeasureSpec,heightMeasureSpec); 来计算ViewGroup中所有子View 的大小 然后通过 getChildCount()获取数量并循环计算总宽高

 measureChildren(widthMeasureSpec,heightMeasureSpec); int count = getChildCount(); for (int i = 0; i < count ; i++) {            View child = getChildAt(i);            //计算过程             if ( (childWidth + lineWidth) > widthMeasure ){                width = Math.max(lineWidth,childWidth);                height += lineHeight;                lineHeight = childHeight;                lineWidth = childWidth;            }else{                lineWidth +=childWidth ;                lineHeight = Math.max(lineHeight,childHeight);            }            if (i == count -1 ){                height += lineHeight ;                width = Math.max(width,lineWidth);            }}

最后得到计算出来的值 通过 setMeasuredDimension方法设置宽高值

  setMeasuredDimension((widthMeasureMode == MeasureSpec.EXACTLY)                ?widthMeasure:width,(heightMeasureMode==MeasureSpec.EXACTLY)                ?heightMeasure:height);

在计算中如果用户指定margin值时 则需要我们单独计算并添加,需要重写generateLayoutParams来获得准确的margin ,可以直接返回 new MarginLayoutParams(getContext(), attrs);

   @Override    public LayoutParams generateLayoutParams(AttributeSet attrs) {        return new MarginLayoutParams(getContext(), attrs);    }
 MarginLayoutParams lp = (MarginLayoutParams) child.getLayoutParams();            int childWidth = child.getMeasuredWidth() + lp.leftMargin + lp.rightMargin;            int childHeight = child.getMeasuredHeight() + lp.topMargin + lp.bottomMargin;

onLayout

确定组件在视图中的位置 如果自定义时 是必须重写的方法

    @Override    protected void onLayout(boolean b, int i, int i1, int i2, int i3) {    }

在onLayout 中 与onMeasure 相同,需要通过 int count = getChildCount(); 获取子View 数量 并通过循环设置每个view的layout

代码是其他自定义view的代码

@Override    protected void onLayout(boolean b, int i, int i1, int i2, int i3) {        int count = getChildCount();        int lineWidth = 0;        int lineHeight = 0;        int top = 0;        int left = 0;        for (int j = 0; j < count; j++) {            View child = getChildAt(j);            MarginLayoutParams lp = (MarginLayoutParams) child.getLayoutParams();            int childWidth = child.getMeasuredWidth() + lp.leftMargin + lp.rightMargin;            int childHeight = child.getMeasuredHeight() + lp.topMargin + lp.bottomMargin;            if ((childWidth + lineWidth) > getMeasuredHeight()) {                top += lineHeight;                left = 0;                lineHeight = childHeight;                lineWidth = childWidth;            } else {                lineHeight = Math.max(lineHeight, childHeight);                lineWidth += childWidth;            }            int lc = left + lp.leftMargin;            int tc = top + lp.topMargin;            int rc = lc + child.getMeasuredWidth();            int bc = tc + child.getMeasuredHeight();            child.layout(lc, tc, rc, bc);            left += childHeight;        }    }

draw

根据位置和大小,将组件画出来

 @Override    protected void onDraw(Canvas canvas) {        super.onDraw(canvas);                mPath.reset();        int originY = 300;        int halfWaveLen = mItemWaveLength/2;        mPath.moveTo(-mItemWaveLength+dx,originY+dy);        for (int i = -mItemWaveLength;i<=getWidth()+mItemWaveLength;i+=mItemWaveLength){            mPath.rQuadTo(halfWaveLen/2,-50,halfWaveLen,0);            mPath.rQuadTo(halfWaveLen/2,50,halfWaveLen,0);        }        mPath.lineTo(getWidth(),getHeight());        mPath.lineTo(0,getHeight());        mPath.close();        canvas.drawPath(mPath,mPaint);        canvas.drawPath(path,mPaint1);    }

onDraw 中 主要是通过在canvas上进行绘制连显示图片

view 在绘制的时候会通过上面这三个方法来确定view 的大小,位置,和其中的内容 ,最终显示到界面上

更多相关文章

  1. Android(安卓)4.4.4 锁屏界面时间大小修改
  2. Android(安卓)使用Camera 打开预览Demo
  3. Dev Guide_Android(安卓)Basics_Application Fundamentals
  4. Android(安卓)组件化开发ButterKnife配置和相关问题
  5. Android(安卓)获取系统或SDCARD剩余空间信息
  6. Lifecycle-Aware Components生命周期组件 Lifecycle、LiveData
  7. 简单明了 的java、android线程池
  8. 再也不信网上流传的方法了!!android创建组件的真正写法!
  9. Android中使用NavigationView实现抽屉侧滑效果中Menu菜单栏设置

随机推荐

  1. Android(安卓)8.1 FreeForm切换显示异常
  2. android中调试之日志
  3. Android PackageManagerService的启动过
  4. android sdk setup时出现:Failed to fetc
  5. Android不依赖Activity的全局悬浮窗实现
  6. Android 选择器 PickerView实例,时间选择
  7. Android图像开源视图:SmartImageView
  8. android ImageView android:adjustViewBo
  9. 系出名门Android(7) - 控件(View)之ZoomC
  10. Android中Parcelable接口的使用