Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Android M: Canvas strokeWidth and strokeStyle issue while drawing arcs

For the following custom view : If stroke width is 0.01 then in Android M and and pre-M devices(ex:lollipop)

enter image description here

However If stroke width is 0.0f then in Android M and and pre-M devices(ex:lollipop)

enter image description here

Are there changes in stroke width in Android M that should be considered ? Is there a dependecy between Stroke style and stroke width ?

XML layout file:

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context="${relativePackage}.${activityClass}" >

    <com.example.testspeedtestgui.TestView
                    android:id="@+id/testView1"
                    android:layout_width="match_parent"
                    android:layout_height="match_parent"
                    android:layout_alignParentStart="true"
                    android:layout_alignParentEnd="true" 
                    android:layout_alignParentTop="true"
                    android:layout_centerHorizontal="true"
                    android:layout_marginLeft="10dp"
                    android:layout_marginRight="10dp" 
                    />

</RelativeLayout>

The code that implements speedometer.java is shown below :

package com.example.testspeedtestgui;
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Path;
import android.graphics.RectF;
import android.os.Build;
import android.util.AttributeSet;
import android.view.View;

public class TestView extends View {

    private Paint outerLogoPaint;
    private Paint centerOuterPaint;
    private Path outerLogoEdge;


    public TestView(Context context) {
        super(context);
        init(context);
    }

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

    public TestView(Context context, AttributeSet attrs, int defStyle) {
        super(context, attrs, defStyle);
        init(context);
    }
    private void init(Context context) {
        if(Build.VERSION.SDK_INT >= 11){
            this.setLayerType(View.LAYER_TYPE_SOFTWARE, null);
        }
        initDrawingTools();

    }

    private void initDrawingTools() {

        float strokeWidth=0.01f;
        centerOuterPaint=new Paint();
        centerOuterPaint.setAntiAlias(true);
        centerOuterPaint.setColor(Color.BLUE);
        centerOuterPaint.setStrokeWidth(strokeWidth);
        centerOuterPaint.setStrokeCap(Paint.Cap.ROUND);
        centerOuterPaint.setStyle(Paint.Style.STROKE);

        RectF rect = new RectF();
        float angle = getSemicircle(0.025f,0.5f,0.975f,0.5f,rect);
        outerLogoEdge = new Path();
        outerLogoEdge.moveTo(0.025f, 0.495f);
        outerLogoEdge.arcTo(rect, angle, 180);
        outerLogoEdge.moveTo(0.025f, 0.495f);
        outerLogoEdge.lineTo(0.2f, 0.495f);
        //Edge surrounding the lower part of outer semi circle(Logo edge Init) Logo edge Init
        angle = getSemicircle(0.20f,0.5f,0.80f,0.5f,rect);
        outerLogoEdge.arcTo(rect, angle, 180);
        outerLogoEdge.moveTo(0.975f, 0.495f);
        outerLogoEdge.lineTo(0.8f, 0.495f);

    }


    @Override
    protected void onDraw(Canvas canvas) {
        float scale = getWidth();
        canvas.save(Canvas.MATRIX_SAVE_FLAG);
        canvas.scale(scale, scale);
        drawLogo(canvas);
        canvas.restore();

    }

    private void drawLogo(Canvas canvas) {

        canvas.save(Canvas.MATRIX_SAVE_FLAG);
        canvas.drawPath(outerLogoEdge, centerOuterPaint);
        canvas.restore();
    }


    public float getSemicircle(float xStart, float yStart, float xEnd,
            float yEnd, RectF ovalRectOUT) {

        float centerX = xStart + ((xEnd - xStart) / 2);
        float centerY = yStart + ((yEnd - yStart) / 2);

        double xLen = (xEnd - xStart);
        double yLen = (yEnd - yStart);
        float radius = (float) (Math.sqrt(xLen * xLen + yLen * yLen) / 2);

        RectF oval = new RectF(centerX - radius,
                centerY - radius, centerX + radius,
                centerY + radius);

        ovalRectOUT.set(oval);

        double radStartAngle = 0;
        radStartAngle = Math.atan2(yStart - centerY, xStart - centerX);
        float startAngle = (float) Math.toDegrees(radStartAngle);

        return startAngle;

    }


}

From the code TestView.java , centerOuterPaint.setStrokeWidth(strokeWidth) seems to cause the issue.

This is part of my app module and doesnt work on Android M. Tested on Nexus 5 running Android 6.0 .

source code at https://github.com/vyshas/SpeedometerTest

like image 681
Vyshakh Amarnath Avatar asked Sep 14 '15 16:09

Vyshakh Amarnath


1 Answers

You have a couple of problems here:

  1. Never use canvas.save(Canvas.MATRIX_SAVE_FLAG); Instead just use canvas.save().

Note: if possible, use the parameter-less save(). It is simpler and faster than individually disabling the saving of matrix or clip with this method.

  1. You are drawing everything at microscopic level in the range of (0...1). And then you are scaling it up nearly a hundred folds. This is bad. canvas.scale() should not be used this way. Instead try drawing your elements at the normal scale itself.

    You can use canvas.getHeight() and canvas.getWidth() to get the height and width of the view you have. Based on this detail, draw the arc and the line.

like image 196
Henry Avatar answered Nov 10 '22 17:11

Henry