Lesson 151. Drawing. PathEffect

Lesson 151. Drawing. PathEffect


In this lesson:

– consider PathEffect objects

PathEffect has several heirs that can influence the objects we draw. Consider the examples of their use.

Let’s create a project:

Project name: P1511_PathEffect
Build Target: Android 2.3.3
Application name: PathEffect
Package name: ru.startandroid.develop.p1511patheffect
Create Activity: MainActivity

CornerPathEffect

The CornerPathEffect effect is simply rounding corners. The radius is rounded to the entrance.

we write in MainActivity.java:

package ru.startandroid.develop.p1511patheffect;

import android.app.Activity;
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.CornerPathEffect;
import android.graphics.Paint;
import android.graphics.Path;
import android.os.Bundle;
import android.view.View;

public class MainActivity extends Activity {

  @Override
  protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(new DrawView(this));
  }

  class DrawView extends View {

    Path path;
    Paint p1;
    Paint p2;
    Paint p3;

    public DrawView(Context context) {
      super(context);
      path = new Path();
      path.rLineTo(100, 300);
      path.rLineTo(100, -100);
      path.rLineTo(100, 300);

      p1 = new Paint(Paint.ANTI_ALIAS_FLAG);
      p1.setStyle(Paint.Style.STROKE);
      p1.setStrokeWidth(3);

      p2 = new Paint(p1);
      p2.setColor(Color.GREEN);
      p2.setPathEffect(new CornerPathEffect(25));

      p3 = new Paint(p1);
      p3.setColor(Color.BLUE);
      p3.setPathEffect(new CornerPathEffect(50));

    }

    @Override
    protected void onDraw(Canvas canvas) {
      canvas.drawARGB(80, 102, 204, 255);

      canvas.translate(100, 100);
      canvas.drawPath(path, p1);

      canvas.translate(250, 0);
      canvas.drawPath(path, p2);

      canvas.translate(250, 0);
      canvas.drawPath(path, p3);

    }

  }

}

We look at the code. We create a Path consisting of three lines. We create three brushes with different colors: black with no effects, green with a rounded circle with a radius of 25, and blue with a rounded 50. And we draw the figure three times.

result:

DiscretePathEffect

DiscretePathEffect allows you to get a broken line with a straight line. The resulting broken line will consist of fragments, and we can affect the length of these fragments (the first parameter of the constructor) and the degree of fracture (the second parameter).

rewrite the class DrawView:

class DrawView extends View {
      
      Path path;
      Paint p1;
      Paint p2;
      Paint p3;
      
      public DrawView(Context context) {
        super(context);
        path = new Path();
        path.rLineTo(100, 300);
        path.rLineTo(100, -100);
        path.rLineTo(100, 300);
        
        p1 = new Paint(Paint.ANTI_ALIAS_FLAG);
        p1.setStyle(Paint.Style.STROKE);
        p1.setStrokeWidth(3);
        
        p2 = new Paint(p1);
        p2.setColor(Color.GREEN);
        p2.setPathEffect(new DiscretePathEffect(10,5));
        
        p3 = new Paint(p1);
        p3.setColor(Color.BLUE);
        p3.setPathEffect(new DiscretePathEffect(10,15));
        
      }
      
      @Override
      protected void onDraw(Canvas canvas) {
        canvas.drawARGB(80, 102, 204, 255);
        
        canvas.translate(100, 100);
        canvas.drawPath(path, p1);
        
        canvas.translate(250, 0);
        canvas.drawPath(path, p2);

        canvas.translate(250, 0);
        canvas.drawPath(path, p3);
        
      }
      
    }

For the green line we use the fracture degree – 5, and for the blue – 15. The length of the fragments = 10.

result:

DashPathEffect

With DashPathEffect, we can get a dashed line from a solid line. We are required to specify the length of the plot to be sketched and the length of the plot to be sketched, that is, “Empty.” This combination will then be used cyclically to draw the entire line.

rewrite the class DrawView:

class DrawView extends View {
      
      Path path;
      Paint p1;
      Paint p2;
      Paint p3;
      
      public DrawView(Context context) {
        super(context);
        path = new Path();
        path.rLineTo(100, 300);
        path.rLineTo(100, -100);
        path.rLineTo(100, 300);
        
        p1 = new Paint(Paint.ANTI_ALIAS_FLAG);
        p1.setStyle(Paint.Style.STROKE);
        p1.setStrokeWidth(7);
        
        p2 = new Paint(p1);
        p2.setColor(Color.GREEN);
        p2.setPathEffect(new DashPathEffect(new float[] { 30, 10}, 0));
        
        p3 = new Paint(p1);
        p3.setColor(Color.BLUE);
        p3.setPathEffect(new DashPathEffect(new float[] { 50, 10, 5, 10 }, 25));
        
      }
      
      @Override
      protected void onDraw(Canvas canvas) {
        canvas.drawARGB(80, 102, 204, 255);
        
        canvas.translate(100, 100);
        canvas.drawPath(path, p1);
        
        canvas.translate(250, 0);
        canvas.drawPath(path, p2);

        canvas.translate(250, 0);
        canvas.drawPath(path, p3);
        
      }
      
    }

For the green line, we set the length of the output section = 30, the length of the void = 10. We put these values ​​in the array and pass to the DashPathEffect constructor the first parameter. The second parameter is indented, we do not use it.

For the blue line, we specify a slightly more complex sequence: 50 print, 10 blank, 5 print, 10 blank. That is, the principle is probably already clear. The system will alternately use values ​​from the array to determine the length of the drawn piece of the line and the length of the next void. Indentation is used in 25.

result:

Green shedding consists of segments of length 30 and voids of length 10. And blue of segment length 50, voids 10, segment 5, voids 10. In the blue line, the first segment looks shorter than the other large ones. This triggered a retreat of 25. If you hang this retreat in a loop, the line will come to life and go to a place that looks pretty impressive.

PathDashPathEffect

PathDashPathEffect allows you to draw a dotted line, but you can use your Path object as a dotted line.

rewrite the class DrawView:

class DrawView extends View {
      
      Path path;
      Path pathStamp;
      Paint p1;
      Paint p2;
      Paint p3;
      Paint p4;
      
      public DrawView(Context context) {
        super(context);
        path = new Path();
        path.addRect(-100, 0, 100, 500, Path.Direction.CW);
        
        pathStamp = new Path();
        pathStamp.lineTo(-10, -10);
        pathStamp.lineTo(10, 0);
        pathStamp.lineTo(-10, 10);
        pathStamp.close();
        
        p1 = new Paint(Paint.ANTI_ALIAS_FLAG);
        p1.setStyle(Paint.Style.STROKE);
        p1.setStrokeWidth(20);
        
        p2 = new Paint(p1);
        p2.setColor(Color.GREEN);
        p2.setPathEffect(new PathDashPathEffect(pathStamp, 20, 0, PathDashPathEffect.Style.MORPH));
        
        p3 = new Paint(p1);
        p3.setColor(Color.BLUE);
        p3.setPathEffect(new PathDashPathEffect(pathStamp, 20, 0, PathDashPathEffect.Style.ROTATE));
        
        p4 = new Paint(p1);
        p4.setColor(Color.RED);
        p4.setPathEffect(new PathDashPathEffect(pathStamp, 20, 10, PathDashPathEffect.Style.TRANSLATE));
        
      }
      
      @Override
      protected void onDraw(Canvas canvas) {
        canvas.drawARGB(80, 102, 204, 255);
        
        canvas.translate(120, 100);
        canvas.drawPath(path, p1);
        
        canvas.translate(250, 0);
        canvas.drawPath(path, p2);

        canvas.translate(250, 0);
        canvas.drawPath(path, p3);

        canvas.translate(250, 0);
        canvas.drawPath(path, p4);
      }
      
    }

We create a path object with a rectangle and pathStamp in the form of an arrow. Next, hang the PathDashPathEffect effect on the brush. Its constructor accepts:

is a path object to use as a dotted line

– the distance between the dotted line

– indentation from the beginning

– style of effect

result:

Lines consist of arrows (pathStamp object). The distance between them = 20. Help styles do not provide reasonable information. In my observations, I can assume the following:

PathDashPathEffect.Style.MORPH – cuts the dotted line at corners (visible on green line)

PathDashPathEffect.Style.ROTATE – Correctly works with corners (seen in blue line)

PathDashPathEffect.Style.TRANSLATE – does not return pathStamp in the direction of the baseline (seen in red)

For the red line I used a small indentation, it is visible – the arrows are not from the corner. Again, by indenting the loop you will get a lively line.

SumPathEffect and ComposePathEffect

They allow us to combine the two effects that are fed to them.

ComposePathEffect will apply one effect first, then the second result and output the result. SumPathEffect – Apply one effect to the desired shape, output the result, then apply the second effect to the desired shape, and output the result.

rewrite the class DrawView:

class DrawView extends View {
      
      Path path;
      Paint p1;
      Paint p2;
      Paint p3;
      Paint p4;
      Paint p5;
      
      public DrawView(Context context) {
        super(context);
        path = new Path();
        path.addRect(-100, 0, 100, 500, Path.Direction.CW);
      
        PathEffect pe1 = new CornerPathEffect(100);
        PathEffect pe2 = new DashPathEffect(new float[] { 20, 5}, 0);
        PathEffect pe3 = new ComposePathEffect(pe2, pe1);
        PathEffect pe4 = new SumPathEffect(pe1, pe2);
        
        p1 = new Paint(Paint.ANTI_ALIAS_FLAG);
        p1.setStyle(Paint.Style.STROKE);
        p1.setStrokeWidth(3);
        
        p2 = new Paint(p1);
        p2.setColor(Color.GREEN);
        p2.setPathEffect(pe1);
        
        p3 = new Paint(p1);
        p3.setColor(Color.BLUE);
        p3.setPathEffect(pe2);
        
        p4 = new Paint(p1);
        p4.setColor(Color.RED);
        p4.setPathEffect(pe3);
        
        p5 = new Paint(p1);
        p5.setColor(Color.YELLOW);
        p5.setPathEffect(pe4);
        
      }
      
      @Override
      protected void onDraw(Canvas canvas) {
        canvas.drawARGB(80, 102, 204, 255);
        
        canvas.translate(120, 100);
        canvas.drawPath(path, p1);
        
        canvas.translate(250, 0);
        canvas.drawPath(path, p2);

        canvas.translate(250, 0);
        canvas.drawPath(path, p3);

        canvas.translate(250, 0);
        canvas.drawPath(path, p4);
        
        canvas.translate(250, 0);
        canvas.drawPath(path, p5);        
      }
      
    }

We create 4 effects.

pe1 – rounding

pe2 – intermittent shedding

pe3 is a combination, pe1 will be applied first, then pe2 will be used

pe4 – the sum of the line will be drawn with effect pe1 and effect pe2

result:

The green rectangle is rounded (pe1). Blue is drawn intermittently (pe2). The red is first rounded, then made intermittent (pe1, then pe2). Yellow is simply a derivation of both effects separately (pe1 and pe2).

In ComposePathEffect, the order of effects matters. Let’s slightly change the previous example

class DrawView extends View {
      
      Path path;
      Paint p1;
      Paint p2;
      Paint p3;
      Paint p4;
      Paint p5;
      
      public DrawView(Context context) {
        super(context);
        path = new Path();
        path.addRect(-100, 0, 100, 500, Path.Direction.CW);
        
        
        PathEffect pe1 = new CornerPathEffect(100);
        PathEffect pe2 = new DiscretePathEffect(15, 10);
        PathEffect pe3 = new ComposePathEffect(pe1, pe2);
        PathEffect pe4 = new ComposePathEffect(pe2, pe1);
        
        
        p1 = new Paint(Paint.ANTI_ALIAS_FLAG);
        p1.setStyle(Paint.Style.STROKE);
        p1.setStrokeWidth(7);
        
        p2 = new Paint(p1);
        p2.setColor(Color.GREEN);
        p2.setPathEffect(pe1);
        
        p3 = new Paint(p1);
        p3.setColor(Color.BLUE);
        p3.setPathEffect(pe2);
        
        p4 = new Paint(p1);
        p4.setColor(Color.RED);
        p4.setPathEffect(pe3);
        
        p5 = new Paint(p1);
        p5.setColor(Color.YELLOW);
        p5.setPathEffect(pe4);
        
      }
      
      @Override
      protected void onDraw(Canvas canvas) {
        canvas.drawARGB(80, 102, 204, 255);
        
        canvas.translate(120, 100);
        canvas.drawPath(path, p1);
        
        canvas.translate(250, 0);
        canvas.drawPath(path, p2);

        canvas.translate(250, 0);
        canvas.drawPath(path, p3);

        canvas.translate(250, 0);
        canvas.drawPath(path, p4);
        
        canvas.translate(250, 0);
        canvas.drawPath(path, p5);        
      }
      
    }

pe1 – rounding

pe2 – scrapped

pe3 – first applied pe2, then pe1

pe4 – first applied pe1, then pe2

result:

The red figure is the result of first applying the break, then rounding. That is, the rounding was already applied to the break and it came out smooth.

And the yellow figure is the result of first rounding, then breaking. That is, the hack was applied to an already rounded rectangle.

I’ve used Path everywhere, but these effects can also be used when drawing canvas objects, such as Canvas.drawRect or Canvas.drawCircle

In the next lesson:

– we work with Picture




Discuss in the forum [11 replies]

Leave a Comment