1.setStyle(Paint.Style style)

FILL: FILL the interior Paint.Style.FILL_AND_STROKE: FILL the interior and STROKE Paint.Style

Example code:


public class PaintViewBasic extends View {
    private Paint mPaint;

    public PaintViewBasic(Context context) {
        super(context);
        mPaint = new Paint();
    }

    public PaintViewBasic(Context context, @Nullable AttributeSet attrs) {
        super(context, attrs);
        mPaint = new Paint();
    }

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

    private void drawStyle( Canvas canvas ) {

        mPaint.setColor(Color.RED);// Set the color of the brush
        mPaint.setTextSize(60);// Set the text size
        mPaint.setStrokeWidth(5);// Set the brush width
        mPaint.setAntiAlias(true);// Set the anti-aliasing function. True indicates anti-aliasing. False indicates that this function is not required

        mPaint.setStyle(Paint.Style.STROKE);
        canvas.drawCircle(200.200.160,mPaint);

        mPaint.setStyle(Paint.Style.FILL);
        canvas.drawCircle(200.600.160,mPaint);

        mPaint.setStyle(Paint.Style.FILL_AND_STROKE);
        canvas.drawCircle(200.1000.160,mPaint); }}Copy the code

2.setStrokeCap(Paint.Cap cap)

Paint.Cap.ROUND(ROUND) Paint.Cap.SQUARE(SQUARE) Note: The extra area is the Cap. It’s like adding a hat to the original line, so it’s called a hat


    private void drawStrokeCap(Canvas canvas) {
        Paint paint = new Paint();

        paint.setAntiAlias(true);
        paint.setStrokeWidth(200);
        paint.setColor(Color.parseColor("#00ff00"));
        paint.setStrokeCap(Paint.Cap.BUTT);       // Line cap, i.e. drawn line with rounded corners at both ends, butt, no rounded corners
        canvas.drawLine(200.200.500.200, paint);

        paint.setColor(Color.parseColor("#ff0000"));
        paint.setStrokeCap(Paint.Cap.ROUND);       // Line cap, that is, whether the drawn line has rounded corners at both ends, ROUND, rounded corners
        canvas.drawLine(200.500.500.500, paint);

        paint.setColor(Color.parseColor("#0000ff"));
        paint.setStrokeCap(Paint.Cap.SQUARE);       // Line cap, that is, whether the drawn line has rounded corners, squares, and rectangles at both ends
        canvas.drawLine(200.800.500.800, paint);
    }
Copy the code

3.setStrokeJoin(Paint.Join join)

Join.MITER Paint.Join.Round Paint.Join.BEVEL


  private void drawStrokeJoin( Canvas canvas ) {
        Paint paint = new Paint();

        paint.setAntiAlias( true );
        paint.setStrokeWidth( 80 );
        paint.setStyle(Paint.Style.STROKE ); // The default is paint.style.fill
        paint.setColor( Color.parseColor("#0000ff")); Path path =new Path();
        path.moveTo(100.100);
        path.lineTo(400.100);
        path.lineTo(100.300);
        paint.setStrokeJoin(Paint.Join.MITER);
        canvas.drawPath(path, paint);

        path.moveTo(100.500);
        path.lineTo(400.500);
        path.lineTo(100.700);
        paint.setStrokeJoin(Paint.Join.ROUND);
        canvas.drawPath(path, paint);

        path.moveTo(100.900);
        path.lineTo(400.900);
        path.lineTo(100.1100); paint.setStrokeJoin(Paint.Join.BEVEL); canvas.drawPath(path, paint); }}Copy the code

4.setPathEffect(PathEffect effect)

Sets the effect of drawing paths, such as dotted lines

CornerPathEffect:

The purpose of this class is to connect the angles between the connecting line segments of the Path in a smoother way, similar to the effect of arcs and tangents. In general, a CornerPathEffect is instantiated by specifying a CornerPathEffect(float radius) with a specific radius of the arc.

DashPathEffect:

The purpose of this class is to dash the Path segment. The constructor is DashPathEffect(float[] intervals, float offset), where intervals are dashed ON and OFF arrays, whose length must be greater than or equal to 2, and phase is the offset when drawing.

DiscretePathEffect:

The purpose of this class is to break up the line segment of the Path, so that the effect is to break up the original Path. Generally, DiscretePathEffect(float segmentLength,float deviation) is used to construct an instance of DiscretePathEffect, where segmentLength specifies the maximum segmentLength and deviation specifies the deviation.

PathDashPathEffect:

A Path graph the function of this class is used to fill the current Path, its constructor for PathDashPathEffect (Path shape, float advance, float phase, PathDashPathEffect. Stylestyle). Shape is the padding, advance is the spacing, phase is the offset, and style is a free enumeration of the class. There are three cases: style.rotate, style.morph, and style.translate. In the ROTATE case, the graph is rotated to an Angle consistent with the movement direction of the next segment. In the MORPH case, the graph is connected to the next segment through stretching or compression. In the TRANSLATE case, the graph is connected to the next segment through position translation.

ComposePathEffect:

ComposePathEffect (PathEffect outerpe,PathEffect innerPE). This class takes two PathEffect parameters to construct an instance of ComposePathEffect. Then add the effect of the outerpe to the innerPE.

SumPathEffect:

For overlay effects, this class also requires two PathEffect arguments SumPathEffect(PathEffect first,PathEffect Second), but unlike ComposePathEffect, when rendered, The effects of the two parameters are shown independently, and then the two effects are simply superimposed together to display.

About parameter Phase

In the two classes with phase parameters, if the value of the phase parameter keeps changing, the graph will keep changing with the offset. At this time, the line will look like it is moving.


private float phase;
    private PathEffect[] effects;
    private  int[] colors;

    private void drawPathEffect(Canvas canvas) {
        mPaint.setStyle(Paint.Style.STROKE);
        mPaint.setStrokeWidth(4);
        // Create and initialize the Path
        Path path = new Path();
        path.moveTo(0.0);
        for (int i = 1; i <= 35; i++) {
            // Generate 15 points, randomly generate their coordinates, and link them into a Path
            path.lineTo(i * 20, (float) Math.random() * 60);
        }
        // Initialize seven colors
        colors = new int[]{Color.BLACK, Color.BLUE, Color.CYAN, Color.GREEN, Color.MAGENTA, Color.RED,
                Color.GRAY};


        // Fill the background with white
        canvas.drawColor(Color.WHITE);
        effects = new PathEffect[7];
        // ------- start to initialize the effect of paths in 7
        // Use the path effect
        effects[0] = null;
        // Use the CornerPathEffect path effect
        effects[1] = new CornerPathEffect(10);
        // Initialize DiscretePathEffect
        effects[2] = new DiscretePathEffect(3.0 f.5.0 f);
        Initialize DashPathEffect
        effects[3] = new DashPathEffect(new float[] {20.10.5.10}, phase);
        // Initialize PathDashPathEffect
        Path p = new Path();
        p.addRect(0.0.8.8, Path.Direction.CCW);
        effects[4] = new PathDashPathEffect(p, 12, phase, PathDashPathEffect.Style.ROTATE);
        // Initialize PathDashPathEffect
        effects[5] = new ComposePathEffect(effects[2], effects[4]);
        effects[6] = new SumPathEffect(effects[4], effects[3]);
        // move the canvas to 8,8 and start painting
        canvas.translate(8.8);
        // Use 7 different path effects,7 different colors in turn to draw paths
        for (int i = 0; i < effects.length; i++) {
            mPaint.setPathEffect(effects[i]);
            mPaint.setColor(colors[i]);
            canvas.drawPath(path, mPaint);
            canvas.translate(0.200);
        }
        // Change the phase value to animate the effect
        phase += 1;
        invalidate();
    }
Copy the code

5.setShadowLayer(float radius, float dx, float dy, int shadowColor)

Shadow making: can be used for all shapes (rectangle, circle, etc.), text, etc.


    private void drawShadowLayer(Canvas canvas) {
        // Create Paint object
        Paint paint1 = new Paint();
        paint1.setTextSize(100);
        // Set the color
        paint1.setColor(Color.BLACK);
        // Set the shadow (soft edge, X displacement, Y displacement, shadow color)
        paint1.setShadowLayer(10.5.5, Color.GRAY);
        // Solid rectangle & its shadow
        canvas.drawText("I love you.".20.100,paint1);
        Paint paint2 = new Paint();
        paint2.setTextSize(100);
        paint2.setColor(Color.GREEN);
        paint2.setShadowLayer(10.6.6, Color.GRAY);
        canvas.drawText("You're so stupid.".20.200,paint2);

        // Cx and cy are the coordinates of the dot
        int radius = 80;
        int offest = 40;
        int startX = radius + offest;
        int startY = radius + offest + 200;

        Paint paint3 = new Paint();
        SetShadowLayer is invalid if hardware acceleration is not turned off
        setLayerType(LAYER_TYPE_SOFTWARE, null);
        paint3.setShadowLayer(20, -20.10, Color.DKGRAY);
        canvas.drawCircle(startX, startY, radius, paint3);
        paint3.setStyle(Paint.Style.STROKE);
        paint3.setStrokeWidth(5);
        canvas.drawCircle(startX + radius * 2 + offest, startY, radius, paint3);
    }
Copy the code

6.setXfermode(Xfermode xfermode)

Xfermode is called transition mode. We can also directly call it image mixing mode, because the so-called “transition” is actually a kind of image mixing. This method is quite similar to setColorFilter mentioned above. A look at the API documentation shows that there are, indeed, three subclasses: AvoidXfermode, PixelXorXfermode, and PorterDuffXfermode, which implement much more complex functionality than the three subclasses of setColorFilter.

Since AvoidXfermode, PixelXorXfermode has both been marked out of date, so this time the focus is on PorterDuffXfermode that is still in use:

PorterDuffXfermode

This class also has a constructor with only one parameter, PorterDuffXfermode(porterduff.mode Mode). Although the constructor has only one parameter in the signature list, it can achieve a lot of cool graphics effects!! PorterDuffXfermode is the meaning of graph mixing mode. The concept of PorterDuffXfermode originally came from Tomas Proter and Tom Duff of SIGGRAPH. The concept of mixed graph greatly promoted the development of graphics and graphics. Extended to computer graphics and image science, like Adobe and AutoDesk, many famous design software can be said to be affected to a certain extent, and our name PorterDuffXfermode also comes from the name combination of these two people PorterDuff, So what can PorterDuffXfermode do? Let’s start with an image from the API DEMO:

This picture vividly illustrates the function of blending graphics to some extent. Two graphics, one circle and one side, can be combined to produce different effects through certain calculation. Android provides 18 modes in API (two more ADD and OVERLAY modes than the above) :

ADD: saturation addition, the addition of image saturation, not commonly used

CLEAR: Clears the image

DARKEN: DARKEN. Darker colors overwrite lighter colors. If they are the same shade, mix

DST: only the target image is displayed

DST_ATOP: Draw [target image] where the source image and target image intersect, and draw [source image] where the source image does not intersect. The effect at the intersection is affected by the alpha of the source image and target image

DST_IN: only draw [target image] where the source image intersects the target image, and the rendering effect is affected by the transparency of the corresponding place of the source image

DST_OUT: only draw [target image] where the source image and target image do not intersect, and filter according to the alpha of the source image at the intersection. If the source image is completely opaque, it will be completely filtered; if the source image is completely transparent, it will not be filtered

DST_OVER: Places the destination image above the source image

LIGHTEN: LIGHTEN, contrary to DARKEN, DARKEN and LIGHTEN generate image results related to Android’s definition of depth of color value

MULTIPLY: MULTIPLY, the pixel color value of the source image multiplied by the pixel color value of the target image divided by 255 to obtain the pixel color value of the mixed image

Superposition of OVERLAY:

SCREEN: Color filter, color balance, keep the white part of the two layers, the dark part is covered

SRC: Displays only the source image

SRC_ATOP: Draw [source image] where the source image intersects with the target image, and draw [target image] where the target image does not intersect. The effect at the intersection is affected by the alpha of the source image and target image

SRC_IN: Draws only where the source image intersects the target image.

SRC_OUT: only draw [source image] where the source image and target image do not intersect. The intersecting area is filtered according to the alpha of the corresponding place of the target image. If the target image is completely opaque, it is completely filtered; if the target image is completely transparent, it is not filtered

SRC_OVER: Places the source image above the destination image

XOR: Draw source and target images outside of where they intersect, where they are affected by the corresponding alpha and color values, and where they intersect is not drawn at all if they are completely opaque


public class PorterDuffView extends View {

    Paint mPaint;
    Context mContext;
    int BlueColor;
    int PinkColor;
    int mWith;
    int mHeight;
    public PorterDuffView(Context context) {
        super(context);
        init(context);
    }
    public PorterDuffView(Context context, AttributeSet attrs) {
        super(context, attrs);
        init(context);
    }

    public PorterDuffView(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        init(context);
    }

    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        super.onMeasure(widthMeasureSpec, heightMeasureSpec);
        mHeight = getMeasuredHeight();
        mWith = getMeasuredWidth();
    }

    private void init(Context context) {
        mContext = context;
        BlueColor = ContextCompat.getColor(mContext, R.color.colorPrimary);
        PinkColor = ContextCompat.getColor(mContext, R.color.colorAccent);
        mPaint = new Paint();
        mPaint.setStyle(Paint.Style.FILL);
        mPaint.setAntiAlias(true);
    }
    private Bitmap drawRectBm(a){
        Paint paint = new Paint(Paint.ANTI_ALIAS_FLAG);
        paint.setColor(BlueColor);
        paint.setStyle(Paint.Style.FILL);
        paint.setAntiAlias(true);
        Bitmap bm = Bitmap.createBitmap(200.200, Bitmap.Config.ARGB_8888);
        Canvas cavas = new Canvas(bm);
        cavas.drawRect(new RectF(0.0.70.70),paint);
        return bm;
    }
    private  Bitmap drawCircleBm(a){
        Paint paint = new Paint(Paint.ANTI_ALIAS_FLAG);
        paint.setColor(PinkColor);
        paint.setStyle(Paint.Style.FILL);
        paint.setAntiAlias(true);
        Bitmap bm = Bitmap.createBitmap(200.200, Bitmap.Config.ARGB_8888);
        Canvas cavas = new Canvas(bm);
        cavas.drawCircle(70.70.35,paint);
        return bm;
    }
    @Override
    protected void onDraw(Canvas canvas) {
        mPaint.setFilterBitmap(false);
        mPaint.setStyle(Paint.Style.FILL);
        mPaint.setTextSize(20);
        RectF recf = new RectF(20.20.60.60);
        mPaint.setColor(BlueColor);
        canvas.drawRect(recf,mPaint);
        mPaint.setColor(PinkColor);
        canvas.drawCircle(100.40.20,mPaint);
        @SuppressLint("WrongConstant") int sc = canvas.saveLayer(0.0,mWith,mHeight, null. Canvas.MATRIX_SAVE_FLAG | Canvas.CLIP_SAVE_FLAG | Canvas.HAS_ALPHA_LAYER_SAVE_FLAG | Canvas.FULL_COLOR_LAYER_SAVE_FLAG |  Canvas.CLIP_TO_LAYER_SAVE_FLAG);int y = 180;
        int x = 50;
        for(PorterDuff.Mode mode : PorterDuff.Mode.values()){
            if(y >= 900){
                y = 180;
                x += 200;
            }
            mPaint.setXfermode(null);
            canvas.drawText(mode.name(),x + 100,y,mPaint);
            canvas.drawBitmap(drawRectBm(),x,y,mPaint);
            mPaint.setXfermode(new PorterDuffXfermode(mode));
            canvas.drawBitmap(drawCircleBm(),x,y,mPaint);
            y += 120;
        }
        mPaint.setXfermode(null);
        // Restore the canvascanvas.restoreToCount(sc); }}Copy the code