Rotating path outside onDraw Method

0

I'm trying to create a simple app that draws a simple figure and then after clicking the button does some affine transformation with the figure. Can you help me finishing onClick method rotate? Thank you a lot. The problem is that I don't know how to pass Canvas to that method from onDraw method in my CanvasView, if it is possible.

MainActivity.java

import android.os.Bundle;
import android.view.View;
import android.widget.Button;

import androidx.appcompat.app.AppCompatActivity;

public class MainActivity extends AppCompatActivity {
    Button button_1;
    Button button_2;
    Button button_3;
    Button button_4;
    private CanvasView customCanvas;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        customCanvas = (CanvasView) findViewById(R.id.signature_canvas);

        button_1 = (Button) findViewById(R.id.btn_1);
        button_1.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                customCanvas.translate();
            }
        });

        button_2 = (Button) findViewById(R.id.btn_2);
        button_2.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                customCanvas.reflect();
            }
        });

        button_3 = (Button) findViewById(R.id.btn_3);
        button_3.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                customCanvas.scale();
            }
        });

        button_4 = (Button) findViewById(R.id.btn_4);
        button_4.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                customCanvas.rotate();//How to pass Canvas from my CanvasView to rotate method?
            }
        });
    }
}

CanvasView.java

import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Matrix;
import android.graphics.Paint;
import android.graphics.Path;
import android.util.AttributeSet;
import android.view.View;

class CanvasView extends View {
    private Paint redPaint;
    private Matrix matrix;
    private Path path;

    public CanvasView(Context c, AttributeSet attrs) {
        super(c, attrs);
        redPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
        redPaint.setStyle(Paint.Style.STROKE);
        redPaint.setColor(0xffff0000);
        redPaint.setStrokeWidth(5);
        matrix = new Matrix();
        path = new Path();
    }

    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
        path.moveTo(400, 400);
        path.lineTo(400, 800);
        path.lineTo(800, 700);
        path.lineTo(600, 600);
        path.lineTo(800, 500);
        path.lineTo(400, 400);
        path.close();
        canvas.drawPath(path, redPaint);
        }
    public void translate() {

    }
    public void reflect() {

    }
    public void scale() {

    }
    public void rotate(Canvas canvas) {
        matrix.reset();
        matrix.setRotate(90, 400, 400);
        path.transform(matrix);
        redPaint.setColor(Color.BLUE);
        canvas.drawPath(path, redPaint);
    }
}

Activity_main.xml

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:layout_gravity="bottom">

    <com.example.lab2.CanvasView
        android:id="@+id/signature_canvas"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:layout_alignParentTop="true"/>

    <LinearLayout
        android:id="@+id/linearLayout"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_alignParentBottom="true"
        android:gravity="bottom"
        android:orientation="horizontal">

        <Button
            android:id="@+id/btn_1"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_weight="1"
            android:text="Перенос"
            android:textSize="8dp" />

        <Button
            android:id="@+id/btn_2"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_weight="1"
            android:text="Отражение"
            android:textSize="8dp" />

        <Button
            android:id="@+id/btn_3"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_weight="1"
            android:text="Масштабирование"
            android:textSize="8dp" />

        <Button
            android:id="@+id/btn_4"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_weight="1"
            android:text="Поворот"
            android:textSize="8dp" />

    </LinearLayout>

</RelativeLayout>
java
android
drawing
asked on Stack Overflow Jun 20, 2020 by Громов Максим • edited Jun 20, 2020 by Jenea Vranceanu

1 Answer

0

You should not pass Canvas into rotate or any other functions. Everything related to modifying canvas should happen within onDraw method.

Update your rotate() method to invoke invalidate() method of View so it will be picked up by the system to be drawn for the next frame:

    public void rotate() {
        matrix.reset();
        matrix.setRotate(90, 400, 400);
        path.transform(matrix);
        redPaint.setColor(Color.BLUE);
        invalidate(); // Invalidated Views should be updated
    }

Why invalidate()?

If we take a look at java docs we will find the next explanation of invalidate() method (and method body):

    /**
     * Invalidate the whole view. If the view is visible,
     * {@link #onDraw(android.graphics.Canvas)} will be called at some point in
     * the future.
     * <p>
     * This must be called from a UI thread. To call from a non-UI thread, call
     * {@link #postInvalidate()}.
     */
    public void invalidate() {
        invalidate(true);
    }
answered on Stack Overflow Jun 20, 2020 by Jenea Vranceanu

User contributions licensed under CC BY-SA 3.0