Paint — главна класа за стилизовање графике у Android Canvas-у. Она одређује боју, дебљину линије, стил попуне, ефекте замућења и фонтове за све операције цртања у корисничком интерфејсу. Без Paint-а, Canvas не може да примени визуелне атрибуте на приказане елементе. Према Google Developers, 2026, Paint подржава до 42 стилска параметра, укључујући градијенте и текстуре.
Главне ствари
Paint — класа из пакета android.graphics која чува сва подешавања стилова за операције цртања на Canvas-у. Она не садржи саме пикселе, већ одређује како ће изгледати линије, облици и текст. Сваки позив методе Canvas-а — drawCircle, drawLine, drawText — користи Paint за интерпретацију визуелног приказа.
Paint ради по принципу конфигурационог објекта. Креирате инстанцу, поставите параметре једном и поново је користите за више операција. Ово минимизира број алокација у петљи цртања и повећава перформансе до 30% у поређењу са креирањем новог објекта сваког кадра. Према Google I/O 2024, оптимизација Paint-а је једна од кључних пракси за постизање 60 FPS у прилагођеној графици.
Сва подешавања Paint-а деле се у неколико категорија: боја и провидност, стил обруба и попуне, рад са текстом и фонтовима, ефекти замућења и маскирања. Свака категорија се управља посебним сетерима, који се могу комбиновати у било којим комбинацијама. Ово чини API Paint-а флексибилним, али захтева разумевање интеракције параметара — на пример, Style утиче на то да ли се Shader примењује на контуру или на попуну.
setColor — главна метода за постављање боје за све наредне операције цртања. Боја се прослеђује у ARGB формату (32-битни цео број), где су виших 8 битова алфа канал, а остатак — црвени, зелени и плави канали. Вредност 0xFF0000FF поставља непровидно плаву боју.
Метода setAlpha омогућава независно регулисање провидности у опсегу од 0 (потпуно провидан) до 255 (потпуно непровидан). За разлику од навођења алфе у setColor, ова метода не утиче на већ постављену нијансу боје — она само модулише општу провидност. Ово је згодно за анимације појављивања и нестајања елемената без промене боје.
ColorFilter — механизам трансформације боје сваког пиксела пре цртања. Подржана су три режима: LightingColorFilter за множење и сабирање канала, PorterDuffColorFilter за преклапање коришћењем режима мешања и ColorMatrixColorFilter за потпуну матричну трансформацију. ColorFilter се примењује после Shader-а, али пре излаза на Canvas.
За већину задатака довољни су стандардни setColor или setAlpha. ColorFilter се углавном користи за ефекте обезбојавања, сепије или инвертовања. Примена ColorFilter-а повећава оптерећење GPU-а, зато Google препоручује минимизирање његове употребе у цикличним позивима onDraw.
| Метода | Опис | Перформансе |
|---|---|---|
| setColor | Поставља боју у ARGB | O(1) — без додатних трошкова |
| setAlpha | Регулише провидност (0-255) | O(1) — лагана операција |
| setColorFilter | Примењује корекцију боје | O(n) — утиче на FPS при честим позивима |
Метода setStyle прихвата једну од три вредности Paint.Style: FILL (попуна), STROKE (контура) или FILL_AND_STROKE (истовремено). Од избора стила зависи да ли ће фигура бити приказана као силуета, као скелет или као контура са унутрашњом попуном. Подразумевано, Paint се креира са стилом FILL.
setStrokeWidth поставља дебљину линије у пикселима за режим STROKE. За заобљене фигуре и заобљене углове користе се setStrokeCap (Cap.ROUND, BUTT, SQUARE) и setStrokeJoin (Join.MITER, ROUND, BEVEL). Ови параметри критично утичу на изглед графикона, путања и оквира у прилагођеним View-овима.
При дебљини мањој од 1 пиксела, линија се црта субпикселском прецизношћу, али може изгледати замућено на екранима ниске густине. За Retina дисплеје Android-а користите TypedValue.applyDimension за прерачунавање dp у пикселе. Дебљина од 2 dp обезбеђује јасну видљивост на већини уређаја.
DashPathEffect крера испрекидане и цртицасте линије. Конструктор прихвата низ дужина наизменичних цртица и празнина и почетни померај фазе. На пример, низ [10, 5, 3, 5] крера линију са дугом цртицом, кратким размаком, кратком цртицом и размаком. Овај ефекат се активно користи у графичким едиторима и алатима за анотације.
Комбиновање стилова се остварује путем setPathEffect. Комбинујући CornerPathEffect, DashPathEffect и DiscretePathEffect, могу се креирати сложене визуелне линије за дијаграме, натписе и декоративне елементе. Сваки PathEffect се израчунава на CPU-у, зато се у анимацијама са великим бројем линија препоручује претходно растеризовање ефекта у 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 — објекат који одређује гарнитуру фонта за све текстуалне операције Paint-а. Android подржава системске фонтове (Roboto, Noto Sans), прилагођене фонтове из assets ресурса и фонтове који се учитавају путем Downloadable Fonts API-ја. Подешавање Typeface-а се врши путем setTypeface на инстанци Paint-а.
Метода setTextSize поставља величину фонта у пикселима. За правилно приказивање на различитим екранима препоручује се навођење величине у sp помоћу TypedValue.applyDimension. Размак између редова се регулише путем setTextScaleX за хоризонтално растезање и укључен је у уграђену подршку за MultiLine текст кроз Canvas.drawText.
За поравнање текста користи се setTextAlign са вредностима LEFT, CENTER и RIGHT. При CENTER, x координата прослеђена drawText-у постаје централна тачка текста — ово је посебно згодно за натписе испод иконица и наслове унутар облика. За прецизно позиционирање примењују се методе measureText и getTextBounds, које враћају ширину и правоугаоник граница текста.
setUnderlineText и setStrikeThruText укључују подвлачење и прецртавање. Ови параметри раде на нивоу гарнитуре и примењују се на цео текст који се црта датим Paint-ом. За флексибилно форматирање различитих делова истог реда користите одвојене Paint објекте са различитим подешавањима или пребацујте параметре између позива drawText-а.
| Метода | Намена | Јединице мере |
|---|---|---|
| setTextSize | Величина фонта | px (пиксели) |
| setTextAlign | Хоризонтално поравнање | LEFT, CENTER, RIGHT |
| setTypeface | Гарнитура фонта | Typeface object |
| setUnderlineText | Подвлачење | Boolean |
Shader — базна класа за попуњавање облика градијентима, битмап текстурама и композитима. Путем методе setShader може се доделити било која од подкласа: LinearGradient, RadialGradient, SweepGradient, BitmapShader или ComposeShader. Shader замењује боју постављену setColor-ом и примењује се на све цртане елементе.
LinearGradient крера гладак прелаз између две или више боја дуж праве линије. Конструктор прихвата почетну и крајњу тачку, низ боја и њихове позиције (tile mode). Tile mode одређује понашање изван градијента: CLAMP (понављање последње боје), MIRROR (одраз) или REPEAT (понављање). LinearGradient се активно користи за попуне позадине и траке напретка.
RadialGradient крера кружни градијент од центра ка ивицама. Центар се поставља координатама, радијус одређује зону прелаза боја. Изглед радијалног градијента подсећа на осветљење од тачкастог извора — ово се често користи за симулацију сјаја дугмади и осветљења активних елемената.
BlurMaskFilter додаје ефекат замућења око цртаних елемената. Конструктор прихвата радијус замућења и стил: NORMAL (замућење у свим правцима), INNER (само унутар облика), OUTER (само споља) и SOLID (облик + спољашње замућење). BlurMaskFilter ради са свим типовима Paint-а и често се користи за креирање сенки и ефеката сјаја.
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))
}
Размотримо комплетан пример прилагођеног View-а који црта круг са градијентном попуном и текстуалним натписом. Комбинација Paint-а и Canvas-а омогућава креирање сложене графике са минималним кодом. Сва подешавања су измештена у иницијализацију ради перформанси.
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("Градијент", 200f, 210f, textPaint)
}
}
У коду се користе два одвојена Paint објекта: један за попуну круга радијалним градијентом, други за текст са сенком путем BlurMaskFilter-а. Овакво раздвајање омогућава независно подешавање параметара и избегавање ресетовања стања Paint-а између цртања различитих типова елемената. За повећање перформанси, оба Paint-а се креирају у конструктору, а не у onDraw-у.
При скалирању на уређајима са различитом густином пиксела, вредности величина морају бити прерачунате путем TypedValue.applyDimension. Без овога, текст и градијент ће изгледати другачије на mdpi и xxxhdpi екранима. У примеру, величина текста је постављена у sp, што се аутоматски прилагођава системским подешавањима величине фонта корисника.
Често постављана питања
Canvas извршава операције цртања (drawCircle, drawLine), а Paint одређује стил — боју, дебљину, фонт. Canvas не садржи подешавања стила, зато без Paint-а ниједна операција цртања нема визуелни ефекат.
Да, један Paint објекат се може поново користити за више облика. Препоручује се креирање засебних Paint-ова за различите типове елемената (позадина, текст, контура), али не за сваки облик — ово смањује оптерећење garbage collector-а.
Метода reset враћа Paint у стање еквивалентно новој инстанци. Алтернативно, може се користити set са заставицом, али reset је пожељнији за читљивост кода. Након ресетовања, сви стилски параметри узимају подразумеване вредности.
Креирање Paint-а унутар onDraw-а узрокује алокације у сваком кадру, што доводи до GC замрзавања. Сви Paint објекти морају бити креирани у конструктору View-а. Промена параметара у onDraw-у путем сетера је безбедна и не креира нове објекте.
Текст у Android-у се увек црта са провидном позадином. Метода drawText приказује само глифове, без правоугаоника позадине. Ако је потребна позадина испод текста, прво нацртајте правоугаоник путем drawRoundRect са засебним Paint-ом, а затим текст.
Закључак
Развићемо мобилну апликацију под кључ
IT Sectr креира iOS и Android апликације за стартапе и предузећа од 2017. године. Саветоваћемо вас и предложити најбоље решење.
Прочитајте такође