Keyguard之LockPatternView学习

LockPatternView.java


When a View object'smeasure() method returns, itsgetMeasuredWidth() andgetMeasuredHeight() values must be set, along with those for all of thatView object's descendants.

View.java

protected final void setMeasuredDimension(int measuredWidth, int measuredHeight) {
    mMeasuredWidth = measuredWidth;
    mMeasuredHeight = measuredHeight;

    mPrivateFlags |= PFLAG_MEASURED_DIMENSION_SET;
}

public final int getMeasuredHeight() {
    return mMeasuredHeight & MEASURED_SIZE_MASK;
}

public final int getMeasuredWidth() {
    return mMeasuredWidth & MEASURED_SIZE_MASK;
}

我们可以复写onMeasure方法,计算出我们期望的view的宽度和高度值,并调用setMeasuredDimension方法设置,这样,父View通过getMeasuredWidth和getMeasuredHeight方法,就能获得我们View的值,为下一步layout做好准备。


下面分析LockPatternView的onMesure方法的实现。

protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
    final int minimumWidth = getSuggestedMinimumWidth();
    final int minimumHeight = getSuggestedMinimumHeight();
    int viewWidth = resolveMeasured(widthMeasureSpec, minimumWidth);
    int viewHeight = resolveMeasured(heightMeasureSpec, minimumHeight);

    //到这里,该View的宽度和高度可以认为已基本计算完成,只是还需要根据此View自定义的aspect属性来做些处理
    switch (mAspect) {
        case ASPECT_SQUARE:
            //正方行的view,则宽和高需要一致,如不一致,取其较小的作为最终的
            viewWidth = viewHeight = Math.min(viewWidth, viewHeight);
            break;
        case ASPECT_LOCK_WIDTH:
            //固定宽度,则高度如果比宽度大,则需要变成跟宽度一致
            viewHeight = Math.min(viewWidth, viewHeight);
            break;
        case ASPECT_LOCK_HEIGHT:
            //固定高度,则宽度如果比高度大,则需要变成跟高度一致
            viewWidth = Math.min(viewWidth, viewHeight);
            break;
    }
    //最重要的,调用这个方法把View对自己宽度和高度的计算结果反馈给parent
    setMeasuredDimension(viewWidth, viewHeight);
}
该view自定义的一个属性:aspect
<declare-styleable name="LockPatternView">
    <!-- Aspect to use when drawing LockPatternView. Choices are "square"(default), "lock_width" or "lock_height" -->
    <attr name="aspect" format="string" />
</declare-styleable>

继续分析getSuggestedMinimumWidth方法

下面是View.java中相关的三个方法:

/**
 * Returns the suggested minimum width that the view should use. This
 * returns the maximum of the view's minimum width and the background's minimum width
 * When being used in {@link #onMeasure(int, int)}, the caller should still
 * ensure the returned width is within the requirements of the parent.
 */
//The caller should still ensure the returned width is within the requirements of the parent.
protected int getSuggestedMinimumWidth() {
    return (mBackground == null) ? mMinWidth : max(mMinWidth, mBackground.getMinimumWidth());
}

/**
 * Returns the minimum width of the view.
 */
public int getMinimumWidth() {
    return mMinWidth;
}

/**
 * Sets the minimum width of the view. It is not guaranteed the view will
 * be able to achieve this minimum width (for example, if its parent layout
 * constrains it with less available width).
 */
//It is not guaranteed the view will be able to achieve this minimum width.
public void setMinimumWidth(int minWidth) {
    mMinWidth = minWidth;
    requestLayout();

}
下面是该view对其中的方法的复写:

public LockPatternView(Context context, AttributeSet attrs) {
    ......
    final Bitmap bitmaps[] = { mBitmapBtnDefault, mBitmapBtnTouched, mBitmapCircleDefault,
            mBitmapCircleGreen, mBitmapCircleRed };

    //在初始化的过程中,计算用到的五张图片的最大宽度和高度
    for (Bitmap bitmap : bitmaps) {
        mBitmapWidth = Math.max(mBitmapWidth, bitmap.getWidth());
        mBitmapHeight = Math.max(mBitmapHeight, bitmap.getHeight());
    }
}

@Override
//这里把那个宽度*3作为建议的最小宽度:3*3的pattern
protected int getSuggestedMinimumWidth() {
    // View should be large enough to contain 3 side-by-side target bitmaps
    return 3 * mBitmapWidth;
}
继续分析resolveMeasured方法
private int resolveMeasured(int measureSpec, int desired)
{
    int result = 0;
    //传入的measureSpec参数中既包含了大小的信息,又包含了mode的信息,针对不同的mode,有不同的策略
    int specSize = MeasureSpec.getSize(measureSpec);
    switch (MeasureSpec.getMode(measureSpec)) {
        case MeasureSpec.UNSPECIFIED:
            //这种mode下,直接选择我们建议的哪个值
            result = desired;
            break;
        case MeasureSpec.AT_MOST:
            //这种mode下,选择我们传入的和我们建议的之中的较大者
            result = Math.max(specSize, desired);
            break;
        case MeasureSpec.EXACTLY:
        default:
            //对于精确的mode,那就只能采用传入的大小
            result = specSize;
    }
    return result;
}

UNSPECIFIED: This is used by a parent to determine the desired dimension of a child View.
For example, a LinearLayout may call measure() on its child with the height set to UNSPECIFIED
and a width of EXACTLY 240 to find out how tall the child View wants to be given a width of 240 pixels.


EXACTLY: This is used by the parent to impose an exact size on the child.
The child must use this size, and guarantee that all of its descendants will fit within this size.


AT MOST: This is used by the parent to impose a maximum size on the child.
The child must guarantee that it and all of its descendants will fit within this size.


A View object's measured width and measured height values must respect the constraints imposed by theView object's parents. This guarantees that at the end of the measure pass, all parents accept all of their children's measurements. A parentView may callmeasure() more than once on its children. For example, the parent may measure each child once with unspecified dimensions to find out how big they want to be, then call measure() on them again with actual numbers if the sum of all the children's unconstrained sizes is too big or too small (that is, if the children don't agree among themselves as to how much space they each get, the parent will intervene and set the rules on the second pass).


你可能感兴趣的:(Keyguard之LockPatternView学习)