2

I have a custom view (a circle) which is rendered correctly when the app runs. But, the view is not aligned correctly when viewed in the XML preview pane.

Below are the screenshot of preview pane where the alignment is not correct.

enter image description here

Below is the screenshot of the same view with the correct alignment when being drawn on a running app.

enter image description here

Here is the code which defines the custom view -

public class LinearTimerView extends View {

    private Paint arcPaint;
    private RectF rectF;

    private int initialColor;
    private int progressColor;
    private int circleRadiusInDp;

    // The point from where the color-fill animation will start.
    private int startingAngle = 270;

    // The point up-till which user wants the circle to be pre-filled.
    private float preFillAngle;

    public LinearTimerView(Context context,
                           AttributeSet attrs) {
        super(context, attrs);

        TypedArray typedArray = getContext().obtainStyledAttributes(attrs,
                R.styleable.LinearTimerView);

        // Retrieve the view attributes.
        this.circleRadiusInDp =
                (int) typedArray.getDimension(R.styleable.LinearTimerView_radius, 5);
        int strokeWidthInDp =
                (int) typedArray.getDimension(R.styleable.LinearTimerView_strokeWidth, 2);
        this.initialColor =
                typedArray.getColor(R.styleable.LinearTimerView_initialColor,
                        ContextCompat.getColor(getContext(), R.color.colorInitial));
        this.progressColor =
                typedArray.getColor(R.styleable.LinearTimerView_progressColor,
                        ContextCompat.getColor(getContext(), R.color.colorProgress));
        this.startingAngle =
                typedArray.getInt(R.styleable.LinearTimerView_startingPoint, 270);

        // Define the size of the circle.
        rectF = new RectF(
                (int) convertDpIntoPixel(strokeWidthInDp),
                (int) convertDpIntoPixel(strokeWidthInDp),
                (int) convertDpIntoPixel(circleRadiusInDp * 2)
                        + (int) convertDpIntoPixel(strokeWidthInDp),
                (int) convertDpIntoPixel(circleRadiusInDp * 2)
                        + (int) convertDpIntoPixel(strokeWidthInDp));

        arcPaint = new Paint();
        arcPaint.setAntiAlias(true);
        arcPaint.setStyle(Paint.Style.STROKE);
        arcPaint.setStrokeWidth((int) convertDpIntoPixel(strokeWidthInDp));

        typedArray.recycle();
    }

    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);

        try {
            // Grey Circle - This circle will be there by default.
            arcPaint.setColor(initialColor);
            canvas.drawCircle(rectF.centerX(), rectF.centerY(),
                    (int) convertDpIntoPixel(circleRadiusInDp), arcPaint);

            // Green Arc (Arc with 360 angle) - This circle will be animated as time progresses.
            arcPaint.setColor(progressColor);
            canvas.drawArc(rectF, startingAngle, preFillAngle, false, arcPaint);
        } catch (NullPointerException ex) {
            ex.printStackTrace();
        }
    }

    /**
     * Method to get the degrees up-till which the arc is already pre-filled.
     * @return
     */
    public float getPreFillAngle() {
        return preFillAngle;
    }

    public void setPreFillAngle(float preFillAngle) {
        this.preFillAngle = preFillAngle;
    }

    /**
     * Method to get the starting point of the angle
     * @return
     */
    public int getStartingPoint() {
        return startingAngle;
    }

    public void setStartingPoint(int startingPointInDegrees) {
        this.startingAngle = startingPointInDegrees;
    }

    /**
     * Method to convert DPs into Pixels.
     */
    private float convertDpIntoPixel(float dp) {
        float scale = getResources().getDisplayMetrics().density;
        return dp * scale + 0.5f;
    } }

How do I fix this?

OneCricketeer
  • 179,855
  • 19
  • 132
  • 245
krtkush
  • 1,378
  • 4
  • 23
  • 46
  • 2
    One reason i can think of is if your view is dependent on runtime measurement it won't be displayed correctly in preview plane. – hardik9850 Feb 03 '17 at 10:55
  • @hardikm Yes, that seems to be the most plausible explanation. – krtkush Feb 04 '17 at 04:42
  • 2
    Your Preview is a Nexus 4. You ran on a Nexus 5X. Always look at the other preview screens to detect layout issues – OneCricketeer Feb 04 '17 at 05:03
  • @cricket_007 Yes! Different devices are rendering it differently. Any idea how I can fix that? – krtkush Feb 17 '17 at 18:04
  • You should be using `dp` instead of pixels – OneCricketeer Feb 17 '17 at 18:40
  • @cricket_007 I am. I have a method which converts dp into pixels. But I still get the problem. On the other hand, if I hard code the values instead of accepting them form the user, the problem does not occur. – krtkush Feb 18 '17 at 06:28
  • Is your circle always the same size? Shouldn't it be determined by the height and width set from the XML layout parameters? – OneCricketeer Feb 18 '17 at 12:39
  • 1
    @cricket_007 I figured. My `onMeasure` was faulty. Hence, the alignment issue. Thanks for the help :) – krtkush Feb 18 '17 at 12:56

1 Answers1

1

Turns out I had not overriden theh onMeasure() method.

I took hint form this answer and was able to fix the problem.

krtkush
  • 1,378
  • 4
  • 23
  • 46