Paint es la clase principal para estilizar gráficos en Android Canvas. Define el color, el grosor de línea, el estilo de relleno, los efectos de desenfoque y las fuentes para todas las operaciones de dibujo en la interfaz de usuario. Sin Paint, Canvas no puede aplicar atributos visuales a los elementos mostrados. Según Google Developers, 2026, Paint admite hasta 42 parámetros de estilo, incluidos degradados y texturas.
Puntos clave
Paint es una clase del paquete android.graphics que almacena toda la configuración de estilo para las operaciones de dibujo en Canvas. No contiene píxeles en sí, sino que determina cómo se verán las líneas, las formas y el texto. Cada llamada al método de Canvas — drawCircle, drawLine, drawText — utiliza Paint para interpretar la representación visual.
Paint funciona según el principio de un objeto de configuración. Crea una instancia, establece los parámetros una vez y la reutiliza para múltiples operaciones. Esto minimiza las asignaciones en el bucle de dibujo y mejora el rendimiento hasta en un 30% en comparación con crear un nuevo objeto en cada fotograma. Según Google I/O 2024, la optimización de Paint es una de las prácticas clave para lograr 60 FPS en gráficos personalizados.
Todos los ajustes de Paint se dividen en varias categorías: color y transparencia, estilo de trazo y relleno, manejo de texto y fuentes, efectos de desenfoque y enmascaramiento. Cada categoría se controla mediante métodos setter independientes que se pueden combinar en cualquier combinación. Esto hace que la API de Paint sea flexible, pero requiere comprender la interacción de los parámetros — por ejemplo, Style afecta si Shader se aplica al trazo o al relleno.
setColor es el método principal para establecer el color de todas las operaciones de dibujo posteriores. El color se pasa en formato ARGB (entero de 32 bits), donde los 8 bits superiores son el canal alfa, y el resto son los canales rojo, verde y azul. El valor 0xFF0000FF establece un color azul opaco.
El método setAlpha permite ajustar la transparencia de forma independiente en el rango de 0 (totalmente transparente) a 255 (totalmente opaco). A diferencia de especificar alfa en setColor, este método no afecta al tono de color ya establecido — solo modula la transparencia general. Esto es útil para animar la aparición y desaparición de elementos sin cambiar los colores.
ColorFilter es un mecanismo para transformar el color de cada píxel antes del renderizado. Se admiten tres modos: LightingColorFilter para multiplicación y suma de canales, PorterDuffColorFilter para superposición mediante modos de mezcla y ColorMatrixColorFilter para transformación matricial completa. ColorFilter se aplica después de Shader pero antes de la salida a Canvas.
Para la mayoría de las tareas, setColor o setAlpha estándar son suficientes. ColorFilter se utiliza principalmente para efectos de desaturación, sepia o inversión. El uso de ColorFilter aumenta la carga de la GPU, por lo que Google recomienda minimizar su uso en llamadas cíclicas a onDraw.
| Método | Descripción | Rendimiento |
|---|---|---|
| setColor | Establece el color en ARGB | O(1) — sin sobrecarga |
| setAlpha | Ajusta la transparencia (0-255) | O(1) — operación ligera |
| setColorFilter | Aplica corrección de color | O(n) — afecta los FPS con llamadas frecuentes |
El método setStyle acepta uno de tres valores de Paint.Style: FILL (relleno), STROKE (contorno) o FILL_AND_STROKE (ambos). La elección del estilo determina si una forma se muestra como silueta, como estructura alambrada o como contorno con relleno interior. De forma predeterminada, Paint se crea con el estilo FILL.
setStrokeWidth establece el grosor de la línea en píxeles para el modo STROKE. Para formas redondeadas y esquinas redondeadas, se utilizan setStrokeCap (Cap.ROUND, BUTT, SQUARE) y setStrokeJoin (Join.MITER, ROUND, BEVEL). Estos parámetros afectan de forma crítica a la apariencia de gráficos, trazados y bordes en las Vistas personalizadas.
Con grosores inferiores a 1 píxel, una línea se dibuja con precisión de subpíxel pero puede parecer borrosa en pantallas de baja densidad. Para las pantallas Retina de Android, utilice TypedValue.applyDimension para convertir dp a píxeles. Un grosor de 2 dp proporciona una visibilidad clara en la mayoría de los dispositivos.
DashPathEffect crea líneas discontinuas y de guiones y puntos. El constructor acepta una matriz de longitudes alternas de guiones y espacios y un desplazamiento de fase inicial. Por ejemplo, la matriz [10, 5, 3, 5] crea una línea con un guión largo, un espacio corto, un guión corto y un espacio. Este efecto se utiliza activamente en editores gráficos y herramientas de anotación.
La combinación de estilos se realiza mediante setPathEffect. Al combinar CornerPathEffect, DashPathEffect y DiscretePathEffect, se pueden crear líneas visuales complejas para gráficos, etiquetas y elementos decorativos. Cada PathEffect se calcula en la CPU, por lo que en animaciones con muchas líneas, se recomienda rasterizar previamente el efecto en un Bitmap.
val paint = Paint().apply {
setStyle(Paint.Style.STROKE)
setStrokeWidth(TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 2f, resources.displayMetrics))
setPathEffect(DashPathEffect(floatArrayOf(10f, 5f, 3f, 5f), 0f))
}
Typeface es un objeto que define la tipografía para todas las operaciones de texto de Paint. Android admite fuentes del sistema (Roboto, Noto Sans), fuentes personalizadas de los recursos de assets y fuentes descargables a través de la API de Downloadable Fonts. Typeface se establece mediante setTypeface en una instancia de Paint.
El método setTextSize establece el tamaño de la fuente en píxeles. Para una visualización correcta en diferentes pantallas, se recomienda especificar el tamaño en sp mediante TypedValue.applyDimension. El interlineado se ajusta usando setTextScaleX para el estiramiento horizontal y es compatible con el texto multilínea integrado a través de Canvas.drawText.
Para la alineación del texto, se utiliza setTextAlign con los valores LEFT, CENTER y RIGHT. Con CENTER, la coordenada x pasada a drawText se convierte en el punto central del texto — esto es especialmente útil para etiquetas debajo de iconos y encabezados dentro de formas. Para un posicionamiento preciso, se utilizan los métodos measureText y getTextBounds, que devuelven la anchura y el rectángulo delimitador del texto.
setUnderlineText y setStrikeThruText activan el subrayado y el tachado respectivamente. Estos parámetros funcionan a nivel de tipografía y se aplican a todo el texto dibujado por este Paint. Para un formateo flexible de diferentes partes de una misma cadena, utilice objetos Paint separados con diferentes configuraciones o alterne los parámetros entre llamadas a drawText.
| Método | Propósito | Unidades |
|---|---|---|
| setTextSize | Tamaño de fuente | px (píxeles) |
| setTextAlign | Alineación horizontal | LEFT, CENTER, RIGHT |
| setTypeface | Tipografía de fuente | Objeto Typeface |
| setUnderlineText | Subrayado | Boolean |
Shader es la clase base para rellenar formas con degradados, texturas de mapa de bits y composición. A través del método setShader, puede asignar cualquiera de sus subclases: LinearGradient, RadialGradient, SweepGradient, BitmapShader o ComposeShader. Shader reemplaza el color establecido por setColor y se aplica a todos los elementos dibujados.
LinearGradient crea una transición suave entre dos o más colores a lo largo de una línea recta. El constructor acepta puntos de inicio y fin, una matriz de colores y sus posiciones (modo de mosaico). El modo de mosaico determina el comportamiento más allá del degradado: CLAMP (repetir el último color), MIRROR (reflejo) o REPEAT (repetir). LinearGradient se utiliza activamente para rellenos de fondo y barras de progreso.
RadialGradient crea un degradado circular desde el centro hacia los bordes. El centro se especifica mediante coordenadas, el radio define el área de transición de color. La apariencia de un degradado radial se asemeja a la iluminación de una fuente puntual — esto se utiliza a menudo para simular el brillo de botones y resaltar elementos activos.
BlurMaskFilter añade un efecto de desenfoque alrededor de los elementos dibujados. El constructor acepta un radio de desenfoque y un estilo: NORMAL (desenfoque en todas direcciones), INNER (solo dentro de la forma), OUTER (solo fuera) y SOLID (forma + desenfoque exterior). BlurMaskFilter funciona con cualquier tipo de Paint y se utiliza a menudo para crear sombras y efectos de brillo.
val paint = Paint().apply {
setShader(LinearGradient(
0f, 0f, width, height,
intArrayOf(Color.RED, Color.BLUE),
null,
Shader.TileMode.CLAMP
))
setMaskFilter(BlurMaskFilter(20f, BlurMaskFilter.Blur.NORMAL))
}
Consideremos un ejemplo completo de una Vista personalizada que dibuja un círculo con un relleno degradado y una etiqueta de texto. La combinación de Paint y Canvas permite crear gráficos complejos con un mínimo de código. Todos los ajustes se trasladan a la inicialización para mejorar el rendimiento.
class GradientCircleView@JvmOverloads constructor(
context: Context,
attrs: AttributeSet? = null
) : View(context, attrs) {
private val fillPaint = Paint().apply {
setShader(RadialGradient(
0f, 0f, 200f,
intArrayOf(Color.CYAN, Color.DKGRAY),
null, Shader.TileMode.CLAMP
))
}
private val textPaint = Paint().apply {
setColor(Color.WHITE)
setTextSize(TypedValue.applyDimension(
TypedValue.COMPLEX_UNIT_SP, 24f, resources.displayMetrics
))
setTextAlign(Paint.Align.CENTER)
setMaskFilter(BlurMaskFilter(5f, BlurMaskFilter.Blur.NORMAL))
}
override fun onDraw(canvas: Canvas) {
super.onDraw(canvas)
canvas.drawCircle(200f, 200f, 150f, fillPaint)
canvas.drawText("Gradient", 200f, 210f, textPaint)
}
}
El código utiliza dos objetos Paint separados: uno para rellenar el círculo con un degradado radial, y el segundo para el texto con una sombra mediante BlurMaskFilter. Esta separación permite configurar los parámetros de forma independiente y evitar el reinicio del estado de Paint entre el dibujo de diferentes tipos de elementos. Para mejorar el rendimiento, ambos objetos Paint se crean en el constructor, no en onDraw.
Al escalar en dispositivos con diferentes densidades de píxeles, los valores de tamaño deben recalcularse mediante TypedValue.applyDimension. Sin esto, el texto y los degradados se verán diferentes en pantallas mdpi y xxxhdpi. En el ejemplo, el tamaño del texto se especifica en sp, que se adapta automáticamente a la configuración del tamaño de fuente del sistema del usuario.
Preguntas frecuentes
Canvas realiza operaciones de dibujo (drawCircle, drawLine), mientras que Paint define el estilo — color, grosor, fuente. Canvas no contiene ajustes de estilo, por lo que sin Paint cualquier operación de dibujo no tiene efecto visual.
Sí, un solo objeto Paint se puede reutilizar para muchas formas. Se recomienda crear objetos Paint separados para diferentes tipos de elementos (fondo, texto, contorno), pero no para cada forma — esto reduce la carga del recolector de basura.
El método reset devuelve Paint a un estado equivalente a una nueva instancia. Alternativamente, se puede usar set con un indicador, pero reset es preferible para la legibilidad del código. Después del restablecimiento, todos los parámetros de estilo adoptan los valores predeterminados.
Crear Paint dentro de onDraw provoca asignación en cada fotograma, lo que genera congelaciones del GC. Todos los objetos Paint deben crearse en el constructor de la Vista. Cambiar los parámetros en onDraw mediante setters es seguro y no crea nuevos objetos.
El texto en Android siempre se dibuja con un fondo transparente. El método drawText solo genera glifos, sin un rectángulo de fondo. Si se necesita un fondo debajo del texto, primero dibuje un rectángulo usando drawRoundRect con un Paint separado, y luego el texto.
Resumen
Desarrollaremos una aplicación móvil llave en mano
IT Sectr crea aplicaciones para iOS y Android para startups y empresas desde 2017. Le asesoraremos y le propondremos la mejor solución.
Lea también