Lollipop内的自定义视图ViewPager仅在不可见时呈现

时间:2015-10-10 22:25:03

标签: android android-fragments android-viewpager android-view

我建立了一个简单的,定制的View类,显示五个彩色圆圈和/或十字架,即:

Custom View Example

它占据Fragment的顶部,并作为RecyclerView顶部的固定标题。整个事情放在ViewPager旁边另一个FragmentFragment只有两个ViewPager。这是第一个。{/ p >

我遇到的问题出现在我的Lollipop设备上。无论何时加载UI,无论是第一次还是配置更改,此View都拒绝呈现。但是很奇怪的是,如果我将ViewPager移动到第二个Fragment(以便包含此View的那个不再可见)并启动配置更改,当我跳转时返回View突然正常呈现。

我很难过。我已经在布局中尝试了其他自定义View类,并且它们都正确呈现,因此它表明我的代码对此类特别错误。

以下是我的View课程的代码:

public class HintTrackerView extends View {

private static final int DEFAULT_NO_OF_CIRCLES = 5;

private static final float DEFAULT_RADIUS_PERCENTAGE = 0.9F;

private static final int[] DEFAULT_ACTIVE_COLOURS = {
        PRIMARY_GREEN,
        createInterimColor(PRIMARY_GREEN, PRIMARY_ORANGE, 0.25F),
        createInterimColor(PRIMARY_GREEN, PRIMARY_ORANGE, 0.5F),
        createInterimColor(PRIMARY_GREEN, PRIMARY_ORANGE, 0.75F),
        PRIMARY_ORANGE
};

private static final int DEFAULT_INACTIVE_COLOR = PRIMARY_GREY;

private int[] activeColors;
private int inactiveColor;

private Paint mFillPaint, mInactivePaint;

private RectF mRectF;

private float mFillRadius;
private int mNoOfCircles;

public HintTrackerView(Context context) {
    super(context, null);
    init();
}

public HintTrackerView(Context context, int[] activeColors) {
    super(context, null);
    init(activeColors);
}

public HintTrackerView(Context context, AttributeSet attrs) {
    super(context, attrs);
    init();
}

private void init() {
    init(DEFAULT_ACTIVE_COLOURS);
}

private void init(int[] colors) {
    this.activeColors = colors;
    inactiveColor = DEFAULT_INACTIVE_COLOR;

    if (mFillRadius == 0) mFillRadius = DEFAULT_RADIUS_PERCENTAGE;
    if (mNoOfCircles == 0) mNoOfCircles = DEFAULT_NO_OF_CIRCLES;

    if (colors.length != mNoOfCircles)
        throw new IllegalArgumentException("Number of colours must match number of circles");

    mFillPaint = new Paint();
    mFillPaint.setAntiAlias(true);
    mFillPaint.setStyle(Paint.Style.FILL);
    mFillPaint.setColor(colors[0]);

    mInactivePaint = new Paint();
    mInactivePaint.setAntiAlias(true);
    mInactivePaint.setDither(true);
    mInactivePaint.setStyle(Paint.Style.STROKE);
    mInactivePaint.setStrokeCap(Paint.Cap.ROUND);
    mInactivePaint.setColor(inactiveColor);

    mRectF = new RectF();
}

@Override
protected void onDraw(Canvas canvas) {

    final int subCanvasSize = getWidth()/ mNoOfCircles;

    for (int i = 0; i < mNoOfCircles; i++) {
        mRectF.set(mRectF.right, 0, mRectF.right + subCanvasSize, getHeight());

        mFillPaint.setColor(activeColors[i]);

        //If hint is has been used, replace symbol with cross
        if (i<3) {
            drawCircle(canvas, mRectF);
        } else {
            drawCross(canvas, mRectF);
        }
    }
}

private void drawCross(Canvas canvas, RectF subCanvasBounds) {

    mInactivePaint.setStrokeWidth(MathUtils.getHypotenuse(Math.min(subCanvasBounds.width(), subCanvasBounds.height()) * 0.1F));

    float innerSubCanvasBounds = Math.min(subCanvasBounds.width(), subCanvasBounds.height());
    float crossLength = MathUtils.getLengthOfFourtyFiveDegreeIsosceles(innerSubCanvasBounds);
    float startX, startY, stopX, stopY;

    startX = subCanvasBounds.centerX() - (crossLength*0.45F);
    startY = subCanvasBounds.centerY() - (crossLength*0.45F);
    stopX = subCanvasBounds.centerX() + (crossLength*0.45F);
    stopY = subCanvasBounds.centerY() + (crossLength*0.45F);

    canvas.drawLine(startX, startY, stopX, stopY, mInactivePaint);

    startX = subCanvasBounds.centerX() + (crossLength*0.45F);
    startY = subCanvasBounds.centerY() - (crossLength*0.45F);
    stopX = subCanvasBounds.centerX() - (crossLength*0.45F);
    stopY = subCanvasBounds.centerY() + (crossLength*0.45F);

    canvas.drawLine(startX, startY, stopX, stopY, mInactivePaint);

}

private void drawCircle(Canvas canvas, RectF subCanvasBounds) {

    float centerX, centerY, radius, viewSize;

    centerX = subCanvasBounds.centerX();
    centerY = subCanvasBounds.centerY();
    viewSize = Math.min(getHeight(), subCanvasBounds.width());
    radius = (viewSize/2) * mFillRadius;

    canvas.drawCircle(centerX, centerY, radius, mFillPaint);

}

}

我的MathUtils类使用了两种方法:

public static float getHypotenuse(float equalLengths) {
    return getHypotenuse(equalLengths, equalLengths);
}

public static float getHypotenuse(float lengthOne, float lengthTwo) {
    return (float) (Math.sqrt(Math.pow(lengthOne, 2) + Math.pow(lengthTwo, 2)));
}

public static float getLengthOfFourtyFiveDegreeIsosceles(float hypotenuse) {
    return (float) (0.5F*hypotenuse*Math.sqrt(2));
}

为什么这个View导致问题的任何想法?

1 个答案:

答案 0 :(得分:1)

问题是由于onDraw()在某些情况下被调用了两次。我只是检查以确保onDraw()被调用,因为我错误地认为每次调用onDraw()时,类构造函数也被调用。当我添加Log次调用以查看每个圆圈/十字架如何测量其边界时,我看到了这个输出:

10-12 17:53:30.106  13829-13829/? E/TAG﹕ Dimens for rectF:
    left = 115.0
    top = 0
    Right = 230.0
    Bottom = 36
10-12 17:53:30.106  13829-13829/? E/TAG﹕ Dimens for rectF:
    left = 230.0
    top = 0
    Right = 345.0
    Bottom = 36
10-12 17:53:30.106  13829-13829/? E/TAG﹕ Dimens for rectF:
    left = 345.0
    top = 0
    Right = 460.0
    Bottom = 36
10-12 17:53:30.106  13829-13829/? E/TAG﹕ Dimens for rectF:
    left = 460.0
    top = 0
    Right = 575.0
    Bottom = 36
10-12 17:53:30.106  13829-13829/? E/TAG﹕ Dimens for rectF:
    left = 575.0
    top = 0
    Right = 690.0
    Bottom = 36
10-12 17:53:30.106  13829-13829/? E/TAG﹕ onDraw
10-12 17:53:30.344  13829-13829/? E/TAG﹕ Dimens for rectF:
    left = 690.0
    top = 0
    Right = 805.0
    Bottom = 36
10-12 17:53:30.345  13829-13829/? E/TAG﹕ Dimens for rectF:
    left = 805.0
    top = 0
    Right = 920.0
    Bottom = 36
10-12 17:53:30.345  13829-13829/? E/TAG﹕ Dimens for rectF:
    left = 920.0
    top = 0
    Right = 1035.0
    Bottom = 36
10-12 17:53:30.345  13829-13829/? E/TAG﹕ Dimens for rectF:
    left = 1035.0
    top = 0
    Right = 1150.0
    Bottom = 36
10-12 17:53:30.345  13829-13829/? E/TAG﹕ Dimens for rectF:
    left = 1150.0
    top = 0
    Right = 1265.0
    Bottom = 36

View width690px,但第二次调用onDraw时,而不是重置mRectF的值返回0,使用了之前的值。这意味着所有圆/十字都是在View的边界之外绘制的。

onDraw开头和for循环之前添加以下行更正了问题:

mRectF.set(0,0,0,0);