前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >专栏 >Android关于Paint你所知道的和不知道的一切

Android关于Paint你所知道的和不知道的一切

作者头像
张风捷特烈
发布于 2018-11-08 10:01:25
发布于 2018-11-08 10:01:25
2.9K04
代码可运行
举报
运行总次数:4
代码可运行
零、前言:

1.曾经也算半个艺术家,深知笔的重要性与复杂性 2.Android里的Paint设置项好多基本上都是setXXX,getXXX,很多文字相关的内容都在Paint里 3.主要由画笔常规配置,画笔类型、画笔特效(线效,着色,滤色)、画笔文字 4.本文暂时还无法覆盖Paint的所有API,能用的吾尽量都会涉及一下

最主要的还是set方法

paint的Set一览.png


一、画笔的常规配置
代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
public void setColor(@ColorInt int color) //设置颜色
public void setAlpha(int a)//设置透明度
public void setARGB(int a, int r, int g, int b)//设置ARGB颜色
public void setStrokeWidth(float width)//设置宽度
public void setAntiAlias(boolean aa)//设置抗锯齿

基本设置.png


二、笔的样式:Paint.Style.:[#FILL|STROKE|FILL_AND_STROKE]
代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
/**
 * 样式测试
 * @param canvas
 */
private void testStyle(Canvas canvas) {
    Rect rect = new Rect(0, 0, 100, 100);
    mRedPaint.setStrokeWidth(15);
    canvas.save();
    
    mRedPaint.setStyle(Paint.Style.FILL);
    canvas.translate(50, 450);
    canvas.drawRect(rect, mRedPaint);
    
    canvas.translate(150, 0);
    mRedPaint.setStyle(Paint.Style.STROKE);
    canvas.drawRect(rect, mRedPaint);
    
    canvas.translate(150 , 0);
    mRedPaint.setStyle(Paint.Style.FILL_AND_STROKE);
    canvas.drawRect(rect, mRedPaint);
    canvas.restore();
    mRedPaint.setStrokeWidth(40);
}

画笔样式测试.png


三、线帽:Paint.Cap.:[#BUTT|ROUND|SQUARE]
1.绘制圆形的点:Paint.Cap.ROUND
代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
/**
 * 绘制圆形的点
 *
 * @param canvas
 */
private void drawPos(Canvas canvas) {
    //设置画笔圆帽
    mRedPaint.setStrokeCap(Paint.Cap.ROUND);
    mRedPaint.setStrokeWidth(20);
    //绘制点
    canvas.drawPoint(100, 100, mRedPaint);
    canvas.drawPoints(new float[]{
            400, 400, 500, 500,
            600, 400, 700, 350,
            800, 300, 900, 300
    }, mRedPaint);
}

绘制圆点.png

2.三种线帽比较

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
/**
 * 线帽型状测试:Paint.Cap.BUTT、Paint.Cap.ROUND、Paint.Cap.SQUARE
 *
 * @param canvas
 */
private void testOfCap(Canvas canvas) {
    canvas.save();
    canvas.translate(150, 200);
    //线帽测试:
    mRedPaint.setStrokeCap(Paint.Cap.BUTT);//无头(默认)
    canvas.drawLine(0, 0, 0, 200, mRedPaint);
    canvas.translate(50, 0);
    mRedPaint.setStrokeCap(Paint.Cap.ROUND);//圆头
    canvas.drawLine(0, 0, 0, 200, mRedPaint);
    canvas.translate(50, 0);
    mRedPaint.setStrokeCap(Paint.Cap.SQUARE);//方头
    canvas.drawLine(0, 0, 0, 200, mRedPaint);
    canvas.restore();
}

线帽型状测试.png


四、线交角测试:Paint.Join.:[#BEVEL|ROUND|MITER]

注意:只有路径绘制的线才有交角效果

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
/**
 * 角型测试:Paint.Join.BEVEL、Paint.Join.ROUND、Paint.Join.MITER
 *
 * @param canvas
 */
private void testOfJoin(Canvas canvas) {
    mRedPaint.setStyle(Paint.Style.STROKE);
    mRedPaint.setStrokeWidth(40);
    Path path = new Path();
    path.moveTo(30, 0);
    path.lineTo(0, 100);
    path.lineTo(100, 100);
    
    canvas.save();
    canvas.translate(600, 100);
    mRedPaint.setStrokeJoin(Paint.Join.BEVEL);//直线(默认)
    canvas.drawPath(path, mRedPaint);
    
    canvas.translate(150, 0);
    mRedPaint.setStrokeJoin(Paint.Join.ROUND);//圆角
    canvas.drawPath(path, mRedPaint);
    
    canvas.translate(150, 0);
    mRedPaint.setStrokeJoin(Paint.Join.MITER);//锐角
    canvas.drawPath(path, mRedPaint);
    canvas.restore();
}

线交角测试.png


五、Paint的路径效果
1.虚线:DashPathEffect(new float[]{a, b, a1, b1...}, offSet)

第一参为显隐线段的长度,第二参为偏移值 下面会动的线是不断改变偏移量:mDashOffSet的结果

虚线效果.gif

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
/**
 * 虚线测试
 *
 * @param canvas
 */
private void dashEffect(Canvas canvas) {
    mEffectPaint = new Paint(mRedPaint);
    mEffectPaint.setStrokeCap(Paint.Cap.BUTT);
    //显示100,隐藏50,显示50,隐藏50,的循环
    mEffectPaint.setPathEffect(new DashPathEffect(new float[]{100, 50, 50, 50}, 0));
    Path path = new Path();
    path.moveTo(100, 650);
    path.lineTo(1000, 650);
    canvas.drawPath(path, mEffectPaint);
    //显示100,隐藏50,显示60,隐藏50,的循环,偏移:mDashOffSet
    mEffectPaint.setPathEffect(new DashPathEffect(new float[]{100, 50, 50, 50}, mDashOffSet));
    Path pathOffset50 = new Path();
    pathOffset50.moveTo(100, 750);
    pathOffset50.lineTo(1000, 750);
    canvas.drawPath(pathOffset50, mEffectPaint);
}

2.折角弧:CornerPathEffect(corner)

动画是不断改变圆角大小:mEffectCorner的结果

折角弧.gif

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
/**
 * 圆角折线
 *
 * @param canvas
 */
private void cornerEffect(Canvas canvas) {
    mEffectPaint.setPathEffect(new CornerPathEffect(mEffectCorner));
    mEffectPaint.setStyle(Paint.Style.STROKE);
    mEffectPaint.setStrokeWidth(40);
    Path path = new Path();
    path.moveTo(550, 550);
    path.lineTo(900, 300);
    path.lineTo(1000, 550);
    canvas.drawPath(path, mEffectPaint);
    //蓝色辅助线
    Paint tempPaint = new Paint();
    tempPaint.setStyle(Paint.Style.STROKE);
    tempPaint.setColor(Color.BLUE);
    tempPaint.setStrokeWidth(2);
    tempPaint.setPathEffect(new DashPathEffect(new float[]{20, 20}, 0));
    Path helpPath = new Path();
    helpPath.moveTo(550, 550);
    helpPath.lineTo(900, 300);
    helpPath.lineTo(1000, 550);
    canvas.drawPath(helpPath, tempPaint);
}

3.离散路径:DiscretePathEffect(小段长,偏移量)

离散路径.png

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
/**
 * 离散路径
 *
 * @param canvas
 */
private void discreteEffect(Canvas canvas) {
    canvas.save();//保存画布状态
    canvas.translate(0, 950);
    //第一个参数:将原来的路径切成多长的线段,越小,所切成的小线段越多
    //第二参数:被切成的每个小线段的可偏移距离。越大,每个线段的可偏移距离就越大。
    Path path = new Path();
    // 定义路径的起点
    path.moveTo(100, 0);
    path.lineTo(600, -100);
    path.lineTo(1000, 0);
    
    mEffectPaint.setPathEffect(new DiscretePathEffect(2, 5));
    mEffectPaint.setStrokeWidth(2);
    canvas.drawPath(path, mEffectPaint);
    canvas.translate(0, 100);
    mEffectPaint.setPathEffect(new DiscretePathEffect(20, 5));
    canvas.drawPath(path, mEffectPaint);
    canvas.restore();//重新储存画布状态
}

4.路径点样:PathDashPathEffect(路径,间距,偏移,样式)

路径样点.gif

通过动图可以很清楚得看出三个样式的区别 动图是不断改变偏移量:mDashOffSet的结果

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
//Path shape:表示[路径点样],这里是一个五角星
//float advance:表示两个[路径点样]间的距离
//float phase:路径绘制偏移距离
//Style style:表示在遇到转角时的过渡样式
// ----Style.ROTATE表示通过旋转[路径点样]来过渡转角;
// ----Style.MORPH表示通过变形[路径点样]来过渡转角;
// ----Style.TRANSLATE表示通过位移[路径点样]来过渡转角。
代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
/**
 * 路径点样路径样式
 *
 * @param canvas
 */
private void PathDashEffect(Canvas canvas) {
    canvas.save();
    canvas.translate(0, 1100);
    Path path = new Path();
    // 定义路径的起点
    path.moveTo(100, 80);
    path.lineTo(600, -100);
    path.lineTo(1000, 80);
    //变形过渡
    mEffectPaint.setPathEffect(new PathDashPathEffect(
            CommonPath.nStarPath(5, 16, 8), 40, mDashOffSet, PathDashPathEffect.Style.ROTATE));
    canvas.drawPath(path, mEffectPaint);
    canvas.restore();
    //旋转过渡
    canvas.save();
    canvas.translate(0, 1200);
    mEffectPaint.setPathEffect(new PathDashPathEffect(
            CommonPath.nStarPath(5, 16, 8), 40, mDashOffSet, PathDashPathEffect.Style.MORPH));
    canvas.drawPath(path, mEffectPaint);
    canvas.restore();
    //移动过渡
    canvas.save();
    canvas.translate(0, 1300);
    mEffectPaint.setPathEffect(new PathDashPathEffect(
            CommonPath.nStarPath(5, 16, 8), 40, mDashOffSet, PathDashPathEffect.Style.TRANSLATE));
    canvas.drawPath(path, mEffectPaint);
    canvas.restore();
}
/**
 * 离散路径
 *
 * @param canvas
 */
private void discreteEffect(Canvas canvas) {
    canvas.save();//保存画布状态
    canvas.translate(0, 950);
    //第一个参数:将原来的路径切成多长的线段,越小,所切成的小线段越多
    //第二参数:被切成的每个小线段的可偏移距离。越大,每个线段的可偏移距离就越大。
    Path path = new Path();
    // 定义路径的起点
    path.moveTo(100, 0);
    path.lineTo(600, -100);
    path.lineTo(1000, 0);
    mEffectPaint.setPathEffect(new DiscretePathEffect(2, 5));
    mEffectPaint.setStrokeWidth(2);
    canvas.drawPath(path, mEffectPaint);
    canvas.translate(0, 100);
    mEffectPaint.setPathEffect(new DiscretePathEffect(20, 5));
    canvas.drawPath(path, mEffectPaint);
    canvas.restore();//重新储存画布状态
}
n角星路径封装:
代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
    /**
     * n角星路径
     *
     * @param num 几角星
     * @param R   外接圆半径
     * @param r   内接圆半径
     * @return n角星路径
     */
    public static Path nStarPath(int num, float R, float r) {
        Path path = new Path();
        float perDeg = 360 / num;
        float degA = perDeg / 2 / 2;
        float degB = 360 / (num - 1) / 2 - degA / 2 + degA;

        path.moveTo(
                (float) (Math.cos(rad(degA + perDeg * 0)) * R + R * Math.cos(rad(degA))),
                (float) (-Math.sin(rad(degA + perDeg * 0)) * R + R));
        for (int i = 0; i < num; i++) {
            path.lineTo(
                    (float) (Math.cos(rad(degA + perDeg * i)) * R + R * Math.cos(rad(degA))),
                    (float) (-Math.sin(rad(degA + perDeg * i)) * R + R));
            path.lineTo(
                    (float) (Math.cos(rad(degB + perDeg * i)) * r + R * Math.cos(rad(degA))),
                    (float) (-Math.sin(rad(degB + perDeg * i)) * r + R));
        }
        path.close();
        return path;
    }

    /**
     * 角度制化为弧度制
     *
     * @param deg 角度
     * @return 弧度
     */
    public static float rad(float deg) {
        return (float) (deg * Math.PI / 180);
    }

5.叠加特效:PathDashPathEffect(e1,e2...)(此处演示:离散效果+样点效果)

特效叠加.gif

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
/**
 * 叠加样式
 *
 * @param canvas
 */
private void composeEffect(Canvas canvas) {
    mEffectPaint.setStyle(Paint.Style.STROKE);
    mEffectPaint.setStrokeWidth(40);
    canvas.save();
    canvas.translate(0, 1400);
    Path path = new Path();
    // 定义路径的起点
    path.moveTo(100, 80);
    path.lineTo(600, -100);
    path.lineTo(1000, 80);
    PathDashPathEffect effect1 = new PathDashPathEffect(
            CommonPath.nStarPath(5, 16, 8), 40, mDashOffSet, PathDashPathEffect.Style.ROTATE);
    DiscretePathEffect effect2 = new DiscretePathEffect(20, 5);
    mEffectPaint.setPathEffect(new ComposePathEffect(effect1, effect2));//离散效果+样点效果
    canvas.drawPath(path, mEffectPaint);
    canvas.restore();
}

6.路径叠加

路径叠加.gif

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
/**
 * 路径叠加
 *
 * @param canvas
 */
private void sumEffect(Canvas canvas) {
    canvas.save();
    canvas.translate(0, 1500);
    Path path = new Path();
    // 定义路径的起点
    path.moveTo(100, 80);
    path.lineTo(600, -100);
    path.lineTo(1000, 80);
    PathDashPathEffect effect1 = new PathDashPathEffect(
            CommonPath.nStarPath(5, 16, 8), 40, mDashOffSet, PathDashPathEffect.Style.ROTATE);
    DiscretePathEffect effect2 = new DiscretePathEffect(20, 5);
    mEffectPaint.setPathEffect(new SumPathEffect(effect1, effect2));//离散效果+样点效果
    canvas.drawPath(path, mEffectPaint);
    canvas.restore();
}

六.着色器:Shader

一个很简单的类,有5个子类:

Shader.png

1.线性渐变:
1).new LinearGradient(渐变起点x,y,渐变终点x,y,渐变色1,渐变色2,渐变模式)

渐变模式:Shader.TileMode.[MIRROR|CLAMP|REPEAT] (图中很形象,就不解释了)

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
        int colorStart = Color.parseColor("#84F125");
        int colorEnd = Color.parseColor("#5825F1");
        canvas.save();
        canvas.translate(mCoo.x, mCoo.y);
        mRedPaint.setStyle(Paint.Style.FILL);
        mRedPaint.setShader(
                new LinearGradient(
                        -200, 0, 200, 0,
                        colorStart, colorEnd,
                        Shader.TileMode.MIRROR

                ));
        canvas.drawRect(-400,-200,400,-100,mRedPaint);

        canvas.translate(0, 150);
        mRedPaint.setShader(
                new LinearGradient(
                        -100, 0, 100, 0,
                        colorStart, colorEnd,
                        Shader.TileMode.CLAMP
                ));
        canvas.drawRect(-400,-200,400,-100,mRedPaint);

        canvas.translate(0, 150);
        mRedPaint.setShader(
                new LinearGradient(
                        -100, 0, 100, 0,
                        colorStart, colorEnd,
                        Shader.TileMode.REPEAT
                ));
        canvas.drawRect(-400,-200,400,-100,mRedPaint);

线性渐变.png


2).多色多点渐变:LinearGradient(渐变起点x,y,渐变终点x,y,颜色数组,位置百分点数组0~1,渐变模式)

多色渐变.png

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
int[] colors = new int[]{
        Color.parseColor("#F60C0C"),//红
        Color.parseColor("#F3B913"),//橙
        Color.parseColor("#E7F716"),//黄
        Color.parseColor("#3DF30B"),//绿
        Color.parseColor("#0DF6EF"),//青
        Color.parseColor("#0829FB"),//蓝
        Color.parseColor("#B709F4"),//紫
};
float[] pos = new float[]{
        1.f / 7, 2.f / 7, 3.f / 7, 4.f / 7, 5.f / 7, 6.f / 7, 1
};

canvas.translate(0, 150);
mRedPaint.setShader(
        new LinearGradient(
                -300, 0, 300, 0,
                colors, pos,
                Shader.TileMode.CLAMP

        ));
canvas.drawRect(-400, -200, 400, -100, mRedPaint);

2.径向渐变:RadialGradient
1).两色渐变:RadialGradient(渐变中心,渐变半径,颜色1,颜色2,渐变模式)
代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
canvas.translate(mCoo.x, mCoo.y);
int colorStart = Color.parseColor("#84F125");
int colorEnd = Color.parseColor("#5825F1");
mRedPaint.setStyle(Paint.Style.FILL);
mRedPaint.setShader(
        new RadialGradient(
               0,0,50,
                colorStart, colorEnd,
                Shader.TileMode.MIRROR

        ));

canvas.drawCircle(0, 0, 150, mRedPaint);

canvas.translate(350, 0);
mRedPaint.setShader(
        new RadialGradient(
                0,0,50,
                colorStart, colorEnd,
                Shader.TileMode.CLAMP

        ));
canvas.drawCircle(0, 0, 150, mRedPaint);


canvas.translate(350, 0);
mRedPaint.setShader(
        new RadialGradient(
                0,0,50,
                colorStart, colorEnd,
                Shader.TileMode.REPEAT

        ));
canvas.drawCircle(0, 0, 150, mRedPaint);

径像渐变.png


2).多色多点径向渐变:

RadialGradient(渐变中心,渐变半径,渐变模式,颜色数组,位置百分点数组0~1,渐变模式)

多色径向渐变.png

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
int[] colors = new int[]{
        Color.parseColor("#F60C0C"),//红
        Color.parseColor("#F3B913"),//橙
        Color.parseColor("#E7F716"),//黄
        Color.parseColor("#3DF30B"),//绿
        Color.parseColor("#0DF6EF"),//青
        Color.parseColor("#0829FB"),//蓝
        Color.parseColor("#B709F4"),//紫
};
float[] pos = new float[]{
        1.f / 7, 2.f / 7, 3.f / 7, 4.f / 7, 5.f / 7, 6.f / 7, 1
};
mRedPaint.setStyle(Paint.Style.FILL);
mRedPaint.setShader(
        new RadialGradient(
                0, 0, 200,
                colors, pos,
                Shader.TileMode.CLAMP
        ));
canvas.drawCircle(0, 0, 250, mRedPaint);
3.扫描渐变:SweepGradient

这个要比上面的简单一点,没有渐变的模式 双色扫描渐变:SweepGradient(中心点x,y,颜色1,颜色2) 多色扫描渐变:SweepGradient(中心点x,y,颜色数组,位置百分点数组0~1)

扫描渐变.png

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
int colorStart = Color.parseColor("#84F125");
int colorEnd = Color.parseColor("#5825F1");
mRedPaint.setStyle(Paint.Style.FILL);
mRedPaint.setShader(
        new SweepGradient(0, 0, colorStart, colorEnd));
canvas.drawCircle(0, 0, 150, mRedPaint);

canvas.translate(400, 0);
int[] colors = new int[]{
        Color.parseColor("#F60C0C"),//红
        Color.parseColor("#F3B913"),//橙
        Color.parseColor("#E7F716"),//黄
        Color.parseColor("#3DF30B"),//绿
        Color.parseColor("#0DF6EF"),//青
        Color.parseColor("#0829FB"),//蓝
        Color.parseColor("#B709F4"),//紫
};
float[] pos = new float[]{
        1.f / 7, 2.f / 7, 3.f / 7, 4.f / 7, 5.f / 7, 6.f / 7, 1
};
mRedPaint.setShader(
        new SweepGradient(0, 0, colors, pos));
canvas.drawCircle(0, 0, 150, mRedPaint);
4.图片着色器:BitmapShader(图片,着色模式x,着色模式y)

用图片的所有像素点作为画笔的颜色

1).文字的图片底色:
代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
//加载图片,生成图片着色器
Bitmap bitmap = BitmapFactory.decodeResource(getResources(),R.mipmap.menu_bg);
BitmapShader bs = new BitmapShader(bitmap, Shader.TileMode.CLAMP,Shader.TileMode.CLAMP);
mRedPaint.setShader(bs);
mRedPaint.setTextSize(150);
mRedPaint.setStrokeWidth(10);
mRedPaint.setStyle(Paint.Style.FILL_AND_STROKE);
canvas.drawText("张风捷特烈", 0, 500, mRedPaint);

图片着色.png

2)路径+图片着色器实现裁剪图片:路径Path相关知识见上一篇:
代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
Bitmap bitmap = BitmapFactory.decodeResource(getResources(), R.mipmap.menu_bg);
BitmapShader bs = new BitmapShader(bitmap, Shader.TileMode.CLAMP, Shader.TileMode.CLAMP);
mRedPaint.setShader(bs);

mRedPaint.setStyle(Paint.Style.FILL);
Path path = CommonPath.nStarPath(8, 500, 250);
canvas.drawPath(path, mRedPaint);

使用路径裁剪图片.png

还有一个ComposeShader比较复杂,以后有需求会专门写一篇


七、颜色过滤器:(具体原理是颜色运算,这里全当玩玩看看吧,暂不深究)
ColorFilter只有三个子类

颜色过滤器.png

1.LightingColorFilter(颜色1,颜色2):

看图体会一下吧...我不说了

LightingColorFilter测试.png

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
        Bitmap mainBitmap = BitmapFactory.decodeResource(getResources(), R.mipmap.menu_bg);
        mRedPaint.setStyle(Paint.Style.FILL);
        mRedPaint.setColorFilter(new LightingColorFilter(
                Color.parseColor("#FF0000"),//红
                Color.parseColor("#0000ff")//蓝
        ));
        canvas.drawBitmap(mainBitmap, 0, 0, mRedPaint);

        canvas.translate(350, 0);
        mRedPaint.setColorFilter(new LightingColorFilter(
                Color.parseColor("#FF0000"),//红
                Color.parseColor("#00ff00")//绿
        ));
        canvas.drawBitmap(mainBitmap, 0, 0, mRedPaint);

        canvas.translate(350, 0);
        mRedPaint.setColorFilter(new LightingColorFilter(
                Color.parseColor("#FF0000"),//红
                Color.parseColor("#000000")//黑
        ));
        canvas.drawBitmap(mainBitmap, 0, 0, mRedPaint);
        canvas.restore();
2.PorterDuffColorFilter(颜色,模式--PorterDuff.Mode):

PorterDuff.Mode一共17中,在Color专题会详述,这里举几个栗子看看

PorterDuffColorFilter测试.png

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
Bitmap mainBitmap = BitmapFactory.decodeResource(getResources(), R.mipmap.menu_bg);
mRedPaint.setStyle(Paint.Style.FILL);

mRedPaint.setColorFilter(new PorterDuffColorFilter(
        Color.parseColor("#0000ff"), PorterDuff.Mode.DARKEN));
canvas.drawBitmap(mainBitmap, 0, 0, mRedPaint);

canvas.translate(350, 0);
mRedPaint.setColorFilter(new PorterDuffColorFilter(
        Color.parseColor("#0000ff"),PorterDuff.Mode.LIGHTEN
));
canvas.drawBitmap(mainBitmap, 0, 0, mRedPaint);

canvas.translate(350, 0);
mRedPaint.setColorFilter(new PorterDuffColorFilter(
        Color.parseColor("#0000ff"),PorterDuff.Mode.SCREEN
));
canvas.drawBitmap(mainBitmap, 0, 0, mRedPaint);

canvas.translate(350, 0);
mRedPaint.setColorFilter(new PorterDuffColorFilter(
        Color.parseColor("#0000ff"),PorterDuff.Mode.OVERLAY
));
canvas.drawBitmap(mainBitmap, 0, 0, mRedPaint);
3.ColorMatrixColorFilter(颜色变换矩阵或25个float数)

刚好前端时间对ColorMatrix有一点研究,这里拿来用用

颜色矩阵.png

ColorMatrix.png

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
        Bitmap mainBitmap = BitmapFactory.decodeResource(getResources(), R.mipmap.menu_bg);
        mRedPaint.setStyle(Paint.Style.FILL);

        //关闭RGB颜色通道(变为黑色),后偏移红色255
        float[] matrix = new float[]{
                -1, 0, 0, 0, 255,
                0, -1, 0, 0, 0,
                0, 0, -1, 0, 0,
                0, 0, 0, 1, 0
        };
        ColorMatrix colorMatrix = new ColorMatrix(matrix);
        mRedPaint.setColorFilter(new ColorMatrixColorFilter(colorMatrix));
        canvas.drawBitmap(mainBitmap, 0, 0, mRedPaint);


        canvas.translate(350, 0);
        //关闭RGB颜色通道(变为黑色),后偏移蓝色255
        float[] matrix2 = new float[]{
                -1, 0, 0, 0, 0,
                0, -1, 0, 0, 0,
                0, 0, -1, 0, 255,
                0, 0, 0, 1, 0
        };
        ColorMatrix colorMatrix2 = new ColorMatrix(matrix2);
        mRedPaint.setColorFilter(new ColorMatrixColorFilter(colorMatrix2));
        canvas.drawBitmap(mainBitmap, 0, 0, mRedPaint);

        canvas.translate(350, 0);
        //关闭RGB颜色通道(变为黑色),后偏移三色255
        float[] matrix3 = new float[]{
                -1, 0, 0, 0, 255,
                0, -1, 0, 0, 255,
                0, 0, -1, 0, 255,
                0, 0, 0, 1, 0
        };
        ColorMatrix colorMatrix3 = new ColorMatrix(matrix3);
        mRedPaint.setColorFilter(new ColorMatrixColorFilter(colorMatrix3));
        canvas.drawBitmap(mainBitmap, 0, 0, mRedPaint);

        canvas.translate(350, 0);

        float[] matrix4 = new float[]{
                //只要把RGB三通道的色彩信息设置成一样:即:R=G=B,
                // 为了保证图像亮度不变,同一个通道中的R+G+B=1
                0.3086f, 0.6094f, 0.0820f, 0, 0,
                0.3086f, 0.6094f, 0.0820f, 0, 0,
                0.3086f, 0.6094f, 0.0820f, 0, 0,
                0, 0, 0, 1, 0
        };
        ColorMatrix colorMatrix4 = new ColorMatrix(matrix4);
        mRedPaint.setColorFilter(new ColorMatrixColorFilter(colorMatrix4));
        canvas.drawBitmap(mainBitmap, 0, 0, mRedPaint);

七、文字相关
代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
字体.setTypeface(Typeface.SANS_SERIF);
对齐方式.setTextAlign(Paint.Align.LEFT);
字体大小.setTextSize(100);
1.对齐方式与内置字体:

对齐:Paint.Align.[#LEFT|RIGHT|CENTER] 内置字体:Typeface.[#DEFAULT|DEFAULT_BOLD|SANS_SERIF|SERIF|MONOSPACE]

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
canvas.save();
canvas.translate(550, 1600);
mTextPaint.setTypeface(Typeface.SANS_SERIF);
mTextPaint.setTextAlign(Paint.Align.LEFT);
mTextPaint.setTextSize(100);
canvas.drawText("SANS_SERIF", 0, 0, mTextPaint);
Paint tempPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
tempPaint.setStrokeWidth(4);
tempPaint.setColor(Color.RED);
tempPaint.setStyle(Paint.Style.STROKE);
canvas.drawRect(0, - 100, mWinSize.x, 0, tempPaint);

canvas.translate(0, 150);
mTextPaint.setTextAlign(Paint.Align.RIGHT);
mTextPaint.setTypeface(Typeface.SERIF);
canvas.drawText("SERIF", 0, 0, mTextPaint);
canvas.drawRect(0, - 100, mWinSize.x, 0, tempPaint);

canvas.translate(0, 150);
mTextPaint.setTypeface(Typeface.MONOSPACE);
mTextPaint.setTextAlign(Paint.Align.CENTER);
canvas.drawText("MONOSPACE", 0, 0, mTextPaint);
canvas.drawRect(0, - 100, mWinSize.x, 0, tempPaint);

canvas.restore();

文字相关.png


2.创建字体:外部字体放在assets目录下
代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
/**
 * 创建字体
 * @param canvas
 */
private void createTypeface(Canvas canvas) {
    mTextPaint.setTextSize(50);
    canvas.save();
    canvas.translate(50, 1600);
    mTextPaint.setTypeface(Typeface.MONOSPACE);
    canvas.drawText("MONOSPACE", 0, 0, mTextPaint);
    //粗体
    canvas.translate(0, 100);
    Typeface typeface = Typeface.create(Typeface.MONOSPACE, Typeface.BOLD);
    mTextPaint.setTypeface(typeface);
    canvas.drawText("MONOSPACE+BOLD", 0, 0, mTextPaint);
    //斜体
    canvas.translate(0, 100);
    Typeface typeface2 = Typeface.create(Typeface.MONOSPACE, Typeface.ITALIC);
    mTextPaint.setTypeface(typeface2);
    canvas.drawText("MONOSPACE+ITALIC", 0, 0, mTextPaint);
    //粗斜体
    canvas.translate(0, 100);
    Typeface typeface3 = Typeface.create(Typeface.MONOSPACE, Typeface.BOLD_ITALIC);
    mTextPaint.setTypeface(typeface3);
    canvas.drawText("MONOSPACE+BOLD_ITALIC", 0, 0, mTextPaint);
    //使用外部字体
    canvas.translate(0, 100);
    Typeface myFont = Typeface.createFromAsset(getContext().getAssets(), "ACHAFSEX.TTF");
    mTextPaint.setTypeface(myFont);
    canvas.drawText("Hello I am Toly", 0, 0, mTextPaint);
    canvas.restore();
}

创建字体.png


3.文字的测量:FontMetrics
1).字体测量类:FontMetrics
代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
    public static class FontMetrics {
        public float   top;//最顶
        public float   ascent;//
        public float   leading;
        public float   descent;
        public float   bottom;//最底
    }
2).SERIF字体测试:(试了一下不同字体这几个属性都不同的,有的字体相差很大)

字体5线.png

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
    /**
     * 获取字体尺寸信息
     * @param canvas
     */
    private void fontMetricsTest(Canvas canvas) {
        canvas.save();
        canvas.translate(100, 500);
        mTextPaint.setTextSize(200);
        mTextPaint.setTypeface(Typeface.SERIF);
        canvas.drawText("I am Toly", 0, 0, mTextPaint);
        //获取字体尺寸
        Paint.FontMetrics fm = mTextPaint.getFontMetrics();

        Log.e(TAG, "top: " + fm.top);
        Log.e(TAG, "ascent: " + fm.ascent);
        Log.e(TAG, "leading: " + fm.leading);
        Log.e(TAG, "descent: " + fm.descent);
        Log.e(TAG, "bottom: " + fm.bottom);

        Paint tempPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
        tempPaint.setStrokeWidth(1);
        tempPaint.setColor(Color.RED);
        tempPaint.setStyle(Paint.Style.STROKE);

        canvas.drawLine(0, fm.top, mWinSize.x, fm.top, tempPaint);

        tempPaint.setColor(Color.MAGENTA);
        canvas.drawLine(0, fm.ascent, mWinSize.x, fm.ascent, tempPaint);

        tempPaint.setColor(Color.parseColor("#4C17F9"));
        canvas.drawLine(0, fm.leading, mWinSize.x, fm.leading, tempPaint);

        tempPaint.setColor(Color.GREEN);
        canvas.drawLine(0, fm.descent, mWinSize.x, fm.descent, tempPaint);

        tempPaint.setColor(Color.parseColor("#E74EDD"));
        canvas.drawLine(0, fm.bottom, mWinSize.x, fm.bottom, tempPaint);

        canvas.restore();
    }
代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
2018-11-05 21:17:35.264 28726-28726/? E/PaintView: top: -209.57031
2018-11-05 21:17:35.264 28726-28726/? E/PaintView: ascent: -185.54688
2018-11-05 21:17:35.264 28726-28726/? E/PaintView: leading: 0.0
2018-11-05 21:17:35.264 28726-28726/? E/PaintView: descent: 48.828125
2018-11-05 21:17:35.264 28726-28726/? E/PaintView: bottom: 50.0

3).获取文字矩形区
代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
String text = "I am Toly";
Rect textRect = new Rect();
mTextPaint.getTextBounds(text, 0, text.length(), textRect);
Log.e(TAG, textRect.toShortString());// [7,-152][886,49]
//绘制矩形
tempPaint.setColor(Color.parseColor("#66F4F628"));
tempPaint.setStyle(Paint.Style.FILL);
canvas.drawRect(textRect, tempPaint);

文字最小矩形区.png


4).文字的变形操作
代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
mTextPaint.setTextScaleX(.5f);//水平伸缩
mTextPaint.setStrikeThruText(true);//删除线
mTextPaint.setUnderlineText(true);//下划线
mTextPaint.setTextSkewX(-.5f);//倾斜

其他效果.png

就先这样吧,还有很多不常用的,以后有需求遇到了,在加吧

后记:捷文规范
1.本文成长记录及勘误表

项目源码

日期

备注

V0.1--无

2018-11-7

Android关于Paint你所知道的和不知道的一切

本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2018.11.07 ,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
暂无评论
推荐阅读
YOLO11-seg分割:包裹分割数据集 | 新颖的多尺度卷积注意力(MSCA),即插即用,助力分割(八)
💡💡💡本文全网首发独家改进:多尺度卷积注意力(MSCA),有效地提取上下文信息,新颖度高,创新十足。
AI小怪兽
2025/01/06
3320
YOLO11-seg分割:SPPF_attention,重新设计加入注意力机制,助力分割
优点:为了利用不同的池化核尺寸提取特征的方式可以获得更多的特征信息,提高网络的识别精度。
AI小怪兽
2024/10/23
9980
YOLO11-seg分割:包裹分割数据集 |SPPF原创自研 | SPPF_attention,能够在不同尺度上更好的、更多的关注注意力特征信息(五)
优点:为了利用不同的池化核尺寸提取特征的方式可以获得更多的特征信息,提高网络的识别精度。
AI小怪兽
2025/01/03
2540
Yolo11实战改进:一文读懂Yolo11到实战
Yolo11是Ultralytics推出的新一代计算机视觉模型,为YOLO家族树立了新的里程碑。它在对象检测、实例分割、图像分类、姿势估计、定向物体检测和对象跟踪等计算机视觉任务上展现了卓越的性能和准确性,相较于YOLOv8有了显著提升。
AI浩
2024/11/18
3.1K0
Yolo11实战改进:一文读懂Yolo11到实战
YOLO11-seg分割:原创自研 | 自研独家创新DSAM注意力 ,基于BiLevelRoutingAttention注意力升级
💡💡💡本文原创自研改进:提出新颖的注意力DSAM(Deformable Bi-level Spatial Attention Module),创新度极佳,适合科研创新,效果秒杀CBAM,Channel Attention+Spartial Attention升级为新颖的 Deformable Bi-level Attention+Spartial Attention
AI小怪兽
2024/10/22
4770
YOLO11-seg分割:包裹分割数据集 | 单头注意力模块,并行结合全局和局部信息提升分割能力 | SHViT CVPR2024(二)
💡💡💡引入了一个单头注意力模块,它固有地防止了头部冗余,同时通过并行结合全局和局部信息来提高准确性
AI小怪兽
2024/12/31
3170
YOLO11-seg分割如何训练自己的数据集(道路缺陷)
💡💡💡本文内容:如何用自己的数据集(道路缺陷)训练yolo11-seg模型以及训练结果可视化;
AI小怪兽
2024/10/21
1.3K0
YOLO11-pose关键点检测:训练实战篇 | 自己数据集从labelme标注到生成yolo格式的关键点数据以及训练教程
💡💡💡本文解决什么问题:教会你如何用自己的数据集转换成对应格式的数据集以及如何训练YOLO11-pose关键点检测
AI小怪兽
2024/10/17
3.9K0
YOLO11-seg分割:包裹分割数据集 | 原创自研 | 一种新颖的跨通道交互的高效率通道注意力EMCA,ECA改进版(四)
💡💡💡本文原创自研创新改进:基于ECA注意力,提出了一种新颖的EMCA注意力(跨通道交互的高效率通道注意力),保持高效轻量级的同时,提升多尺度提取能力
AI小怪兽
2025/01/02
2760
YOLO11-seg分割:包裹分割数据集 | 具有切片操作的SimAM注意力,魔改SimAM助力分割(六)
💡💡💡问题点:SimAM计算整张特征图的像素差平均值时加权可能会忽略小目标的重要性,同时与整体平均值相比可能和背景信息相似,导致加权增强较弱,进而使得SimAM对小目标的增强能力较差。
AI小怪兽
2025/01/04
2570
YOLO11-seg分割:包裹分割数据集 | 全局到局部可控感受野模块GL-CRM ,量身为为多尺度变化而设计| 2024年10月最新成果(七)
💡💡💡GL-CRM是为了更好地处理多尺度变化而设计的。它包括两个主要组件:可控感受野模块(CRM)和全局到局部设计(GL)。CRM灵活地提取和整合具有多个尺度和粒度的特征,而GL架构具有从全局上下文到子块区域再到局部语义信息的层次感知过程。
AI小怪兽
2025/01/05
1500
基于YOLO11的无人机检测系统(Python源码+数据集+Pyside6界面)
💡💡💡本文摘要:基于YOLO11的无人机检测,阐述了整个数据制作和训练可视化过程
AI小怪兽
2025/03/16
1890
基于YOLO11的矿井下移动目标检测系统(Python源码+数据集+Pyside6界面)
💡💡💡本文摘要:基于YOLO11的矿井下移动目标检测,阐述了整个数据制作和训练可视化过程
AI小怪兽
2025/01/09
2610
基于YOLO11的番茄检测系统(Python源码+数据集+Pyside6界面)
💡💡💡本文摘要:基于YOLO11的番茄检测,阐述了整个数据制作和训练可视化过程
AI小怪兽
2025/03/26
3340
YOLO11实战:GC10-DET缺陷检测 |多级特征融合金字塔(HS-FPN),助力缺陷检测(2)
💡💡💡本文独家改进:高层筛选特征金字塔网络(HS-FPN),能够刷选出大小目标,增强模型表达不同尺度特征的能力,助力小目标检测
AI小怪兽
2024/12/27
4330
基于YOLO11的茶叶嫩芽检测系统(Python源码+数据集+Pyside6界面)
💡💡💡本文摘要:基于YOLO11的茶叶嫩芽检测,阐述了整个数据制作和训练可视化过程
AI小怪兽
2025/03/25
1970
基于YOLO11的工件缺陷检测系统(Python源码+数据集+Pyside6界面)
💡💡💡本文摘要:基于YOLO11的工件表面缺陷智能检测系统,阐述了整个数据制作和训练可视化过程
AI小怪兽
2024/12/25
7680
YOLO11实战:NEU-DET | 一种具有切片操作的SimAM注意力的内容引导注意力(CGA)的混合融合方案
💡💡💡创新点:提出了一种具有切片操作的SimAM注意力,增强小目标特征提取能力 + 基于内容引导注意力(CGA)的混合融合方案
AI小怪兽
2025/01/08
2670
YOLO11遥感小目标车辆性能提升 | 通道转置注意力(CTA),多头通道 | IJCAI-24(一)
💡💡💡通道转置注意力: 与SFA不同,通道转置注意力(CTA)采用了不同的策略,沿着通道维度进行自注意力计算,将通道分成多个头。
AI小怪兽
2024/12/24
2550
YOLOv8 训练自己的数据集
本范例我们使用 ultralytics中的YOLOv8目标检测模型训练自己的数据集,从而能够检测气球。
lyhue1991
2023/09/05
3.4K1
YOLOv8 训练自己的数据集
推荐阅读
YOLO11-seg分割:包裹分割数据集 | 新颖的多尺度卷积注意力(MSCA),即插即用,助力分割(八)
3320
YOLO11-seg分割:SPPF_attention,重新设计加入注意力机制,助力分割
9980
YOLO11-seg分割:包裹分割数据集 |SPPF原创自研 | SPPF_attention,能够在不同尺度上更好的、更多的关注注意力特征信息(五)
2540
Yolo11实战改进:一文读懂Yolo11到实战
3.1K0
YOLO11-seg分割:原创自研 | 自研独家创新DSAM注意力 ,基于BiLevelRoutingAttention注意力升级
4770
YOLO11-seg分割:包裹分割数据集 | 单头注意力模块,并行结合全局和局部信息提升分割能力 | SHViT CVPR2024(二)
3170
YOLO11-seg分割如何训练自己的数据集(道路缺陷)
1.3K0
YOLO11-pose关键点检测:训练实战篇 | 自己数据集从labelme标注到生成yolo格式的关键点数据以及训练教程
3.9K0
YOLO11-seg分割:包裹分割数据集 | 原创自研 | 一种新颖的跨通道交互的高效率通道注意力EMCA,ECA改进版(四)
2760
YOLO11-seg分割:包裹分割数据集 | 具有切片操作的SimAM注意力,魔改SimAM助力分割(六)
2570
YOLO11-seg分割:包裹分割数据集 | 全局到局部可控感受野模块GL-CRM ,量身为为多尺度变化而设计| 2024年10月最新成果(七)
1500
基于YOLO11的无人机检测系统(Python源码+数据集+Pyside6界面)
1890
基于YOLO11的矿井下移动目标检测系统(Python源码+数据集+Pyside6界面)
2610
基于YOLO11的番茄检测系统(Python源码+数据集+Pyside6界面)
3340
YOLO11实战:GC10-DET缺陷检测 |多级特征融合金字塔(HS-FPN),助力缺陷检测(2)
4330
基于YOLO11的茶叶嫩芽检测系统(Python源码+数据集+Pyside6界面)
1970
基于YOLO11的工件缺陷检测系统(Python源码+数据集+Pyside6界面)
7680
YOLO11实战:NEU-DET | 一种具有切片操作的SimAM注意力的内容引导注意力(CGA)的混合融合方案
2670
YOLO11遥感小目标车辆性能提升 | 通道转置注意力(CTA),多头通道 | IJCAI-24(一)
2550
YOLOv8 训练自己的数据集
3.4K1
相关推荐
YOLO11-seg分割:包裹分割数据集 | 新颖的多尺度卷积注意力(MSCA),即插即用,助力分割(八)
更多 >
LV.1
自动驾驶ADAS深度学习工程师
目录
  • 零、前言:
    • 最主要的还是set方法
  • 一、画笔的常规配置
  • 二、笔的样式:Paint.Style.:[#FILL|STROKE|FILL_AND_STROKE]
  • 三、线帽:Paint.Cap.:[#BUTT|ROUND|SQUARE]
    • 1.绘制圆形的点:Paint.Cap.ROUND
  • 四、线交角测试:Paint.Join.:[#BEVEL|ROUND|MITER]
  • 五、Paint的路径效果
    • 1.虚线:DashPathEffect(new float[]{a, b, a1, b1...}, offSet)
    • 2.折角弧:CornerPathEffect(corner)
    • 3.离散路径:DiscretePathEffect(小段长,偏移量)
    • 4.路径点样:PathDashPathEffect(路径,间距,偏移,样式)
    • n角星路径封装:
    • 5.叠加特效:PathDashPathEffect(e1,e2...)(此处演示:离散效果+样点效果)
    • 6.路径叠加
  • 六.着色器:Shader
    • 1.线性渐变:
      • 1).new LinearGradient(渐变起点x,y,渐变终点x,y,渐变色1,渐变色2,渐变模式)
      • 2).多色多点渐变:LinearGradient(渐变起点x,y,渐变终点x,y,颜色数组,位置百分点数组0~1,渐变模式)
    • 2.径向渐变:RadialGradient
      • 1).两色渐变:RadialGradient(渐变中心,渐变半径,颜色1,颜色2,渐变模式)
      • 2).多色多点径向渐变:
    • 3.扫描渐变:SweepGradient
    • 4.图片着色器:BitmapShader(图片,着色模式x,着色模式y)
      • 1).文字的图片底色:
      • 2)路径+图片着色器实现裁剪图片:路径Path相关知识见上一篇:
  • 七、颜色过滤器:(具体原理是颜色运算,这里全当玩玩看看吧,暂不深究)
    • ColorFilter只有三个子类
    • 1.LightingColorFilter(颜色1,颜色2):
    • 2.PorterDuffColorFilter(颜色,模式--PorterDuff.Mode):
    • 3.ColorMatrixColorFilter(颜色变换矩阵或25个float数)
  • 七、文字相关
    • 1.对齐方式与内置字体:
    • 2.创建字体:外部字体放在assets目录下
    • 3.文字的测量:FontMetrics
      • 1).字体测量类:FontMetrics
      • 2).SERIF字体测试:(试了一下不同字体这几个属性都不同的,有的字体相差很大)
    • 3).获取文字矩形区
    • 4).文字的变形操作
  • 后记:捷文规范
    • 1.本文成长记录及勘误表
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档