• Android开发之View重写相关API-onLayout,onMeasure,MeasureSpec


     1.onLayout

    android.view.ViewGroup

    protected void onLayout(boolean changed, int l, int t, int r, int b)

    执行layout操作时调用onLayout方法。View要给它的每个Child设定size和position。拥有Children的子类需要重写onLayout方法并且调用每个Child的layout方法。

    参数changed表示view的size或position发生变化。参数l, t, r, b分别表示相对于parent的left, top, right, bottom position。

     2.onMeasure

    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec)

    测量View及其Content,确定measuredWidth和measuredHeight。在方法measure(int, int)中调用。重写onMeasure方法时,需要调用方法setMeasuredDimension(int, int),存储View的measuredWidth和measuredHeight。若存储失败,方法measure(int, int)会抛出异常IllegalStateException。可以调用super.onMeasure(int, int)方法。

    除非MeasureSpec准许更大的size,否则measure的默认实现是background size。子类重写onMeasure(int, int)提供Content的更佳测量。如果onMeasure被重写,子类必须保证measuredWidth和measuredHeight至少是view的minHeight和minWidth。minHeight/Width通过getSuggestedMinimumHight/Width()获取。

    参数width/heightMeasureSpec表示parent强加的horizontal/vertical space要求。

    void android.view.ViewGroup.layout(int l, int t, int r, int b)

    给view及其descendants设定size和position。它正是layout机制的第2个步,每个parent调用它的chlidren的layout操作。使用在measure阶段测量得到的size和position数据完成layout操作。拥有child的子类必须重写onLayout方法,调用每个child的layout操作。

    void android.view.ViewGroup.measureChildren(int widthMeasureSpec, int heightMeasureSpec)

    请View的所有children测量themseles, 测量依据是View的MeasureSpec和padding。忽略处于GONE状态的children,是否GONE状态由getChildMeasureSpec来确定。

    参数width/heightMeasureSpec表示view的width/height要求。

    3.MeasureSpec

    android.view.View.MeasureSpec

    MeasureSpec是View的内部类

    public static class MeasureSpec

    MeasureSpec封装从parent传递给child的layout要求。每个MeasureSpec表示对width/height的要求。MeasureSpec由size和mode组成。可用的mode有3种:

    1. UNSPECIFIED表示parent没有强加给child任何constraint。

    2. EXACTLY表示parent已经确定child的精确size。

    3. AT_MOST表示child可以设定为specified size之内的任何值。

    MeasureSpec实现为int类型,相比object类型,降低了allocation。可以将<size, mode>元组pack和unpack为int类型。

    MeasureSpec定义的常量有:

    private static final int MODE_SHIFT = 30;

    private static final int MODE_MASK  = 0x3 << MODE_SHIFT;

    public static final int UNSPECIFIED = 0 << MODE_SHIFT;

    public static final int EXACTLY     = 1 << MODE_SHIFT;

    public static final int AT_MOST     = 2 << MODE_SHIFT;

    MeasureSpec定义的方法有:

    public static String toString(int measureSpec) { 
        int mode = getMode(measureSpec); 
        int size = getSize(measureSpec);

        StringBuilder sb = new StringBuilder("MeasureSpec: ");

        if (mode == UNSPECIFIED) 
            sb.append("UNSPECIFIED "); 
        else if (mode == EXACTLY) 
            sb.append("EXACTLY "); 
        else if (mode == AT_MOST) 
            sb.append("AT_MOST "); 
        else 
            sb.append(mode).append(" ");

        sb.append(size); 
        return sb.toString(); 
    }

    public static int getSize(int measureSpec) { 
        return (measureSpec & ~MODE_MASK); 
    }

    public static int getMode(int measureSpec) { 
        return (measureSpec & MODE_MASK); 
    }

    public static int makeMeasureSpec(int size, int mode) { 
        return size + mode; 
    }

  • 相关阅读:
    洛谷P6276 [USACO20OPEN]Exercise P(生成函数)
    牛顿迭代求逆元
    线性基求交
    我卷我自己加强
    AGC013 简要题解
    LOJ#6074 「2017 山东一轮集训 Day6」
    JAVA根据下载地址获取文件的Base64
    JS 作用链,箭头函数 this 取值
    Leetcode 1249 移除无效的括号
    Vue的数据绑定
  • 原文地址:https://www.cnblogs.com/JczmDeveloper/p/3822582.html
Copyright © 2020-2023  润新知