Skip to content

裁剪画布 canvas clip path

本文记录如何使用canvas.clipPath(path)方法。

clipPath方法相当于按给定的路径裁剪画布。 根据这个用途,我们可以做出圆角图片的效果。

圆角图片示例

圆角图片是一种常见的设计。Android官方库中并没有直接显示圆角图片的方法。 如果是纯色,渐变色的背景,我们可以用shape的corners来实现圆角。 这里是利用clipPathsuper.onDraw(canvas)之前将画布裁出圆角。需要传入一个Path来指定裁剪范围。

新建一个RoundImageView类,继承自AppCompatImageView

import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.Canvas;
import android.graphics.Path;
import android.util.AttributeSet;

import androidx.appcompat.widget.AppCompatImageView;

public class RoundImageView extends AppCompatImageView {
    private float vw, vh;
    private Path path = new Path();

    private float topLeftR;
    private float topRightR;
    private float botLeftR;
    private float botRightR;

    public RoundImageView(Context context) {
        this(context, null);
    }

    public RoundImageView(Context context, AttributeSet attrs) {
        this(context, attrs, 0);
    }

    public RoundImageView(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        TypedArray typedArray = context.obtainStyledAttributes(attrs, R.styleable.RoundImageView);
        topLeftR = typedArray.getDimensionPixelSize(R.styleable.RoundImageView_topLeftR, 0);
        topRightR = typedArray.getDimensionPixelSize(R.styleable.RoundImageView_topRightR, 0);
        botLeftR = typedArray.getDimensionPixelSize(R.styleable.RoundImageView_botLeftR, 0);
        botRightR = typedArray.getDimensionPixelSize(R.styleable.RoundImageView_botRightR, 0);
        typedArray.recycle();
    }

    @Override
    protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
        super.onLayout(changed, left, top, right, bottom);
        vw = getWidth();
        vh = getHeight();
    }

    @Override
    protected void onDraw(Canvas canvas) {
        path.reset();
        if (vw > topLeftR && vh > topRightR) {
            path.moveTo(topLeftR, 0);
            path.lineTo(vw - topRightR, 0);
            path.quadTo(vw, 0, vw, topRightR);
            path.lineTo(vw, vh - botRightR);
            path.quadTo(vw, vh, vw - botRightR, vh);
            path.lineTo(botLeftR, vh);
            path.quadTo(0, vh, 0, vh - botLeftR);
            path.lineTo(0, topLeftR);
            path.quadTo(0, 0, topLeftR, 0);
            path.close();
            canvas.clipPath(path);
        }
        super.onDraw(canvas);
    }
}

里面使用了TypedArray,需要新增declare-styleable资源。

<resources>
    <declare-styleable name="RoundImageView">
        <attr name="topLeftR" format="dimension" />
        <attr name="topRightR" format="dimension" />
        <attr name="botLeftR" format="dimension" />
        <attr name="botRightR" format="dimension" />
    </declare-styleable>
</resources>

使用这个类。在layout中直接使用。分别定义4个圆角半径参数。给src设置纯色。 如果给定图片,图片内容接触到view端点时,才会看得出有圆角效果。

<com.rustfisher.tutorial2020.customview.view.RoundImageView
    style="@style/RoundIvCube"
    app:botLeftR="8dp"
    app:botRightR="8dp"
    app:topLeftR="8dp"
    app:topRightR="8dp" />

<com.rustfisher.tutorial2020.customview.view.RoundImageView
    style="@style/RoundIvCube"
    app:botLeftR="25dp"
    app:botRightR="25dp"
    app:topLeftR="25dp"
    app:topRightR="25dp" />

<com.rustfisher.tutorial2020.customview.view.RoundImageView
    style="@style/RoundIvCube"
    app:botLeftR="16dp" />

<com.rustfisher.tutorial2020.customview.view.RoundImageView
    style="@style/RoundIvCube"
    app:topLeftR="16dp" />

<com.rustfisher.tutorial2020.customview.view.RoundImageView
    style="@style/RoundIvCube"
    app:botRightR="16dp"
    app:topLeftR="16dp" />

style定义

    <style name="RoundIvCube">
        <item name="android:layout_width">50dp</item>
        <item name="android:layout_height">50dp</item>
        <item name="android:src">#303F9F</item>
        <item name="android:layout_margin">8dp</item>
    </style>

运行结果

可以看到各个图形的圆角。但是我们也能发现有锯齿。这个裁剪方法没能做到光滑圆润的圆角。