Paint几个枚举/常量值以及ShadowLayer阴影效果

Paint API 之—— 枚举/常量值 及 ShadowLayer 阴影效果

在 Android 的 Paint 类中,枚举和常量值用于控制绘制行为和样式,涵盖了填充模式、线条样式、文本对齐方式等多个方面。ShadowLayer 则是一种特殊的阴影效果,用于为绘制内容(如形状或文本)添加投影,提升视觉层次感。以下将详细介绍 Paint 的主要枚举/常量值以及 ShadowLayer 的使用方法。


Paint 的主要枚举/常量值

Paint 类定义了多个枚举和常量,用于配置绘制样式、行为和效果。以下是常见枚举和常量的概述:

1. Paint.Style(绘制样式)

Paint.Style 枚举定义了绘制内容的填充方式,影响形状或路径的呈现方式。

  • Paint.Style.FILL:填充整个形状(内部填充)。
  • Paint.Style.STROKE:仅绘制形状的边框(描边)。
  • Paint.Style.FILL_AND_STROKE:同时填充内部和描边。
  • 用途:控制绘制是填充、描边还是两者兼有。例如,绘制实心矩形用 FILL,绘制空心圆用 STROKE
  • 代码示例
  paint.setStyle(Paint.Style.FILL); // 填充矩形
  canvas.drawRect(50, 50, 150, 100, paint);
2. Paint.Cap(线条端点样式)

Paint.Cap 枚举定义了线条或路径端点的形状,适用于 STROKE 模式。

  • Paint.Cap.BUTT:平直端点(默认,无额外延伸)。
  • Paint.Cap.ROUND:圆形端点(端点为半圆)。
  • Paint.Cap.SQUARE:方形端点(端点延伸半个笔触宽度)。
  • 用途:常用于线条或路径的起点/终点美化,如绘制圆头线条。
  • 代码示例
  paint.setStrokeWidth(10f);
  paint.setStrokeCap(Paint.Cap.ROUND); // 圆形端点
  canvas.drawLine(50, 50, 150, 50, paint);
3. Paint.Join(线条连接样式)

Paint.Join 枚举定义了路径拐角处的连接样式,适用于 STROKE 模式。

  • Paint.Join.MITER:尖角连接(默认,尖锐拐角)。
  • Paint.Join.ROUND:圆角连接(拐角为圆弧)。
  • Paint.Join.BEVEL:斜面连接(平滑切角)。
  • 用途:用于多段路径(如折线或多边形)拐角的样式调整。
  • 代码示例
  paint.setStrokeWidth(10f);
  paint.setStrokeJoin(Paint.Join.ROUND); // 圆角连接
  Path path = new Path();
  path.moveTo(50, 50);
  path.lineTo(100, 100);
  path.lineTo(50, 150);
  canvas.drawPath(path, paint);
4. Paint.Align(文本对齐方式)

Paint.Align 枚举定义了文本绘制时的对齐方式。

  • Paint.Align.LEFT:文本左对齐(默认)。
  • Paint.Align.CENTER:文本中心对齐。
  • Paint.Align.RIGHT:文本右对齐。
  • 用途:控制文本相对于绘制起点的水平对齐,常用于 Canvas.drawText
  • 代码示例
  paint.setTextSize(40f);
  paint.setTextAlign(Paint.Align.CENTER); // 居中对齐
  canvas.drawText("Hello", 100, 100, paint);
5. Paint.FontMetrics(字体度量常量)

Paint.FontMetrics 提供了文本绘制时的垂直度量值,用于精确布局。

  • 主要字段
  • top:文本最顶部的相对位置(负值)。
  • ascent:基线到文本上边缘的距离(负值)。
  • descent:基线到文本下边缘的距离(正值)。
  • bottom:文本最底部的相对位置(正值)。
  • leading:行间距(通常为 0 或小值)。
  • 用途:计算文本高度、行间距或对齐位置。
  • 代码示例
  Paint.FontMetrics metrics = paint.getFontMetrics();
  float textHeight = metrics.descent - metrics.ascent;
6. 其他常量(部分常见标志)
  • Paint.ANTI_ALIAS_FLAG:开启抗锯齿,平滑边缘(默认推荐开启)。
  • Paint.DITHER_FLAG:开启抖动,优化颜色过渡(适用于低色深设备)。
  • Paint.FILTER_BITMAP_FLAG:开启位图过滤,提升缩放质量。
  • 代码示例
  paint = new Paint(Paint.ANTI_ALIAS_FLAG | Paint.DITHER_FLAG);

ShadowLayer 阴影效果

ShadowLayer 是一种特殊的 Paint 效果,通过 Paint.setShadowLayer(float radius, float dx, float dy, int color) 方法为绘制内容(形状、文本等)添加阴影效果。阴影本质是一个模糊的颜色投影,增强立体感。

参数说明
  • radius:模糊半径(float),值越大阴影越模糊。设为 0 则禁用阴影。
  • dx:阴影在 X 轴的偏移量(float),正值向右,负值向左。
  • dy:阴影在 Y 轴的偏移量(float),正值向下,负值向上。
  • color:阴影颜色(int),通常为半透明颜色(如 Color.argb(128, 0, 0, 0))。
使用场景
  • 为文本添加投影(如标题或标签)。
  • 为形状(如按钮、卡片)增加立体感。
  • 模拟光源效果(结合动画调整 dx/dy)。
注意事项
  • 限制ShadowLayer 不支持硬件加速(API 14+ 默认启用硬件加速),需禁用硬件加速或使用软件渲染(View.setLayerType(View.LAYER_TYPE_SOFTWARE, null))。
  • 性能:大半径阴影或复杂路径可能影响性能,建议谨慎使用。
  • 兼容性:API 1+ 支持,但硬件加速限制需注意。
  • 清除阴影:调用 paint.clearShadowLayer() 移除阴影效果。
代码示例

以下是一个自定义 View 示例,展示 ShadowLayer 结合不同 Paint 样式和枚举的效果:

import android.content.Context;
import android.graphics.*;
import android.util.AttributeSet;
import android.view.View;

public class ShadowLayerView extends View {
    private Paint paint;

    public ShadowLayerView(Context context, AttributeSet attrs) {
        super(context, attrs);
        paint = new Paint(Paint.ANTI_ALIAS_FLAG);
        // 禁用硬件加速以支持 ShadowLayer
        setLayerType(LAYER_TYPE_SOFTWARE, null);
    }

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

        // 1. 带阴影的填充矩形
        paint.setStyle(Paint.Style.FILL);
        paint.setColor(Color.BLUE);
        paint.setShadowLayer(10f, 5f, 5f, Color.argb(128, 0, 0, 0)); // 半径10,偏移(5,5),半透明黑
        canvas.drawRect(50, 50, 150, 100, paint);

        // 2. 带阴影的描边圆形(圆形端点)
        paint.setStyle(Paint.Style.STROKE);
        paint.setStrokeWidth(10f);
        paint.setStrokeCap(Paint.Cap.ROUND);
        paint.setColor(Color.RED);
        paint.setShadowLayer(8f, 3f, 3f, Color.argb(128, 0, 0, 0));
        canvas.translate(0, 150);
        canvas.drawCircle(100, 50, 50, paint);

        // 3. 带阴影的文本(居中对齐)
        paint.setStyle(Paint.Style.FILL);
        paint.setTextSize(40f);
        paint.setTextAlign(Paint.Align.CENTER);
        paint.setColor(Color.BLACK);
        paint.setShadowLayer(5f, 2f, 2f, Color.argb(128, 255, 0, 0)); // 红色阴影
        canvas.translate(0, 150);
        canvas.drawText("Shadow Text", 100, 50, paint);

        // 4. 清除阴影并绘制路径(圆角连接)
        paint.clearShadowLayer();
        paint.setStyle(Paint.Style.STROKE);
        paint.setStrokeJoin(Paint.Join.ROUND);
        paint.setColor(Color.GREEN);
        Path path = new Path();
        path.moveTo(50, 50);
        path.lineTo(100, 100);
        path.lineTo(50, 150);
        canvas.translate(0, 150);
        canvas.drawPath(path, paint);
    }
}
  • 运行效果:从上到下依次显示带阴影的填充矩形、描边圆形、带红色阴影的文本,以及无阴影的折线路径(圆角连接)。
  • 动画扩展:通过动态调整 dxdy(配合 ValueAnimator),可以实现阴影移动效果,模拟光源变化。

扩展:Jetpack Compose 中的等效实现

在 Jetpack Compose 中,ShadowLayer 的效果可以通过 Modifier.shadowdrawWithCache 结合 Blur 实现。例如:

import androidx.compose.foundation.Canvas
import androidx.compose.foundation.layout.size
import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.graphics.drawscope.Fill
import androidx.compose.ui.unit.dp

@Composable
fun ShadowExample() {
    Canvas(
        modifier = Modifier
            .size(200.dp)
            .shadow(elevation = 10.dp, shape = RectangleShape) // 添加阴影
    ) {
        drawRect(
            color = Color.Blue,
            topLeft = Offset(50f, 50f),
            size = Size(100f, 50f),
            style = Fill
        )
    }
}
  • 说明Modifier.shadow 提供类似 ShadowLayer 的效果,支持圆角和偏移调整。复杂阴影(如文本或路径的自定义阴影)需使用 drawWithContentBlur

注意事项

  • 枚举选择:合理选择 StyleCapJoin 能显著提升绘图美观度。例如,ROUND 端点和连接适合平滑曲线,MITER 适合锐利边角。
  • ShadowLayer 性能:禁用硬件加速可能导致性能下降,建议在小范围使用或缓存为 Bitmap
  • 与 Shader/PathEffect 的结合ShadowLayer 可与 Shader(渐变填充)或 PathEffect(虚线)组合,创造丰富效果,如带阴影的渐变虚线。
  • 调试:Android SDK 的 ApiDemos 包含 Paint 相关示例,可参考学习。

如果需要更详细的某枚举用法(如 FontMetrics 的精确布局)、ShadowLayer 的动画实现,或 Compose 中的高级阴影效果,请告诉我!

类似文章

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注