自定义View笔记——基础了解

 View的绘制流程是从ViewRoot的PerformTraversals方法开始的,它经过measur.layout和draw三个过程才能将一个view绘制出来,其中measure用来测量View的宽度,layout用来确定View在父容器中放置的位置,draw负责将View绘制在屏幕上面。


  • onMeasure()
         MeasureSpec

              通过MeasureSpec可以帮助我们测量View
            MeasureSpec是一个32位的Int值,高2位是测量的模式,低30位为测量的大小。在计算中使用位运算原因是为了提高并优化效率。
            
            测量模式

         EXACTLY 精准模式 当控件的width或height为具体数值的时候或者match_parent 时系统用的是EXACTLY模式
        
            AT_MOST 即最大模式 控件的width或height为wrap_content 随着控件的子控件或者内容变化而变化
            
            UNSPECIFIED    不指定其大小测量的模式,通常在绘制自定义 View时才会使用
        
            默认 EXACTLY 如果想使用 wrap_content 必须重写 onMeasure();

@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
}
在suprer.onMeasure()方法点击进去看后可以发现最后调用了  setMeasuredDimensionRaw()方法把宽和高设了进去
protected final void setMeasuredDimension(int measuredWidth, int measuredHeight) {
boolean optical = isLayoutModeOptical(this);
if (optical != isLayoutModeOptical(mParent)) {
Insets insets = getOpticalInsets();
int opticalWidth = insets.left + insets.right;
int opticalHeight = insets.top + insets.bottom;

measuredWidth += optical ? opticalWidth : -opticalWidth;
measuredHeight += optical ? opticalHeight : -opticalHeight;
}
setMeasuredDimensionRaw(measuredWidth, measuredHeight);
}

所以可以这么重写onMeasure方法
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
width = MeasureWidth(widthMeasureSpec);
height = MeasureHeight(heightMeasureSpec);
setMeasuredDimension(width, height);
}

private int MeasureHeight(int heightMeasureSpec) {
int result;
int size = MeasureSpec.getSize(heightMeasureSpec);
int mode = MeasureSpec.getMode(heightMeasureSpec);
if (mode == MeasureSpec.EXACTLY) {
result = size;
} else {
result = 200;//默认的值
if (mode == MeasureSpec.AT_MOST) {
result = Math.min(size, result);
}
}
return result;
}

private int MeasureWidth(int widthMeasureSpec) {
int result;
int size = MeasureSpec.getSize(widthMeasureSpec);
int mode = MeasureSpec.getMode(widthMeasureSpec);
if (mode == MeasureSpec.EXACTLY) {
result = size;
} else {
result = 200;
if (mode == MeasureSpec.AT_MOST) {
result = Math.min(size, result);
}
}
return result;
}

       
  • onLayout()
 
 
    onLayout方法是ViewGroup中子View的布局方法,用于放置子View的位置。
    放置子View很简单,只需在重写onLayout方法,然后获取子View的实例,调用子View的layout方法实现布局。
    在实际开发中,一般要配合onMeasure测量方法一起使用。
    下面是一个自定义ViewGroup的Demo,用onLayout和layout实现子View的水平放置,间隔是20px

 
 
//子View的水平间隔
      private final static int padding = 20 ;
@Override
    protected void onLayout(boolean changed, int l, int t, int r, int b) {
// TODO Auto-generated method stub
// 动态获取子View实例
for (int i = 0, size = getChildCount(); i < size; i++) {
View view = getChildAt(i)
;
// 放置子View,宽高都是100
view.layout(l, t, l + 100, t + 100);
l += 100 + padding;
}

}
  • onDraw()
根据名字你就能够判断出,在这里才真正地开始对视图进行绘制。
ViewRoot中的代码会继续执行并创建出一个Canvas对象,然后调用View的draw()方法来执行具体的绘制工作。
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
}
  • 在回调父类方法前实现自己的逻辑,对View来说既是在绘制文本内容前
  • 在回调父类方法后实现自己的逻辑,对View来说既是绘制文本内容后

  • View中其他重要的方法

  •     onFinishInflate()    从Xml中加载组件后回调

  •     onSizeChanger();   组件大小改变时回调

  •     onMeasure();         回调该方法进行测量

  •     onLayout();            回调该方法来确定显示的位置

  •     onTouchEvent();     监听触摸事件时回调
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值