Paint — η κύρια κλάση για τη στυλισμένη γραφικών στο Android Canvas. Καθορίζει το χρώμα, το πάχος γραμμής, το στυλ γεμίσματος, τα εφέ θολώματος και τις γραμματοσειρές για όλες τις λειτουργίες σχεδίασης στο περιβάλλον χρήστη. Χωρίς το Paint, το Canvas δεν μπορεί να εφαρμόσει οπτικά χαρακτηριστικά στα εμφανιζόμενα στοιχεία. Σύμφωνα με το Google Developers, 2026, το Paint υποστηρίζει έως 42 παραμέτρους στυλ, συμπεριλαμβανομένων των gradient και υφών.
Κύρια σημεία
Paint — μια κλάση από το πακέτο android.graphics που αποθηκεύει όλες τις ρυθμίσεις στυλ για λειτουργίες σχεδίασης στο Canvas. Δεν περιέχει τα ίδια τα pixel, αλλά καθορίζει πώς θα εμφανίζονται οι γραμμές, τα σχήματα και το κείμενο. Κάθε κλήση μεθόδου Canvas — drawCircle, drawLine, drawText — χρησιμοποιεί το Paint για την ερμηνεία της οπτικής αναπαράστασης.
Το Paint λειτουργεί με βάση την αρχή ενός αντικειμένου διαμόρφωσης. Δημιουργείτε ένα instance, ορίζετε τις παραμέτρους μία φορά και το επαναχρησιμοποιείτε για πολλές λειτουργίες. Αυτό ελαχιστοποιεί τον αριθμό των δεσμεύσεων στον βρόχο σχεδίασης και αυξάνει την απόδοση έως και 30% σε σύγκριση με τη δημιουργία νέου αντικειμένου κάθε καρέ. Σύμφωνα με το Google I/O 2024, η βελτιστοποίηση του Paint είναι μία από τις βασικές πρακτικές για την επίτευξη 60 FPS σε προσαρμοσμένα γραφικά.
Όλες οι ρυθμίσεις του Paint χωρίζονται σε διάφορες κατηγορίες: χρώμα και διαφάνεια, στυλ περιγράμματος και γεμίσματος, εργασία με κείμενο και γραμματοσειρές, εφέ θολώματος και μάσκας. Κάθε κατηγορία διαχειρίζεται από ξεχωριστές μεθόδους setter που μπορούν να συνδυαστούν σε οποιονδήποτε συνδυασμό. Αυτό κάνει το Paint API ευέλικτο, αλλά απαιτεί κατανόηση της αλληλεπίδρασης των παραμέτρων — για παράδειγμα, το Style επηρεάζει αν το Shader εφαρμόζεται στο περίγραμμα ή στο γέμισμα.
setColor — η κύρια μέθοδος για τον ορισμό χρώματος για όλες τις επόμενες λειτουργίες σχεδίασης. Το χρώμα μεταδίδεται σε μορφή ARGB (32-bit ακέραιος αριθμός), όπου τα ανώτερα 8 bit είναι το κανάλι άλφα και τα υπόλοιπα είναι τα κανάλια κόκκινου, πράσινου και μπλε. Η τιμή 0xFF0000FF ορίζει αδιαφανές μπλε χρώμα.
Η μέθοδος setAlpha επιτρέπει την ανεξάρτητη ρύθμιση της διαφάνειας σε εύρος από 0 (εντελώς διαφανές) έως 255 (εντελώς αδιαφανές). Σε αντίθεση με τον καθορισμό άλφα στο setColor, αυτή η μέθοδος δεν επηρεάζει την ήδη ορισμένη απόχρωση χρώματος — απλώς διαμορφώνει τη συνολική διαφάνεια. Αυτό είναι βολικό για κινούμενα σχέδια εμφάνισης και εξαφάνισης στοιχείων χωρίς αλλαγή χρώματος.
ColorFilter — μηχανισμός μετασχηματισμού χρώματος κάθε pixel πριν από τη σχεδίαση. Υποστηρίζονται τρεις λειτουργίες: LightingColorFilter για πολλαπλασιασμό και πρόσθεση καναλιών, PorterDuffColorFilter για επικάλυψη με χρήση λειτουργιών ανάμειξης και ColorMatrixColorFilter για πλήρη μετασχηματισμό μήτρας. Το ColorFilter εφαρμόζεται μετά το Shader, αλλά πριν από την έξοδο στο Canvas.
Για τις περισσότερες εργασίες, αρκούν τα τυπικά setColor ή setAlpha. Το ColorFilter χρησιμοποιείται κυρίως για εφέ αποχρωματισμού, sepia ή αντιστροφής. Η χρήση του 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 ορίζει το πάχος γραμμής σε pixel για τη λειτουργία STROKE. Για στρογγυλεμένα σχήματα και στρογγυλεμένες γωνίες χρησιμοποιούνται setStrokeCap (Cap.ROUND, BUTT, SQUARE) και setStrokeJoin (Join.MITER, ROUND, BEVEL). Αυτές οι παράμετροι επηρεάζουν κρίσιμα την εμφάνιση γραφημάτων, διαδρομών και πλαισίων σε προσαρμοσμένα View.
Σε πάχος μικρότερο από 1 pixel, η γραμμή σχεδιάζεται με υποπίξελ ακρίβεια, αλλά μπορεί να φαίνεται θολή σε οθόνες χαμηλής πυκνότητας. Για οθόνες Retina Android χρησιμοποιήστε TypedValue.applyDimension για μετατροπή dp σε pixel. Το πάχος 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 στο instance του Paint.
Η μέθοδος setTextSize ορίζει το μέγεθος γραμματοσειράς σε pixel. Για σωστή εμφάνιση σε διαφορετικές οθόνες, συνιστάται να ορίζετε το μέγεθος σε sp χρησιμοποιώντας TypedValue.applyDimension. Το διάστιχο ρυθμίζεται μέσω setTextScaleX για οριζόντια επέκταση και περιλαμβάνεται στην ενσωματωμένη υποστήριξη κειμένου MultiLine μέσω Canvas.drawText.
Για στοίχιση κειμένου χρησιμοποιείται setTextAlign με τιμές LEFT, CENTER και RIGHT. Στο CENTER, η συντεταγμένη x που μεταδίδεται στο drawText γίνεται το κεντρικό σημείο του κειμένου — αυτό είναι ιδιαίτερα βολικό για λεζάντες κάτω από εικονίδια και τίτλους εντός σχημάτων. Για ακριβή τοποθέτηση χρησιμοποιούνται οι μέθοδοι measureText και getTextBounds, που επιστρέφουν το πλάτος και το ορθογώνιο ορίων του κειμένου.
Οι setUnderlineText και setStrikeThruText ενεργοποιούν την υπογράμμιση και τη διαγραφή αντίστοιχα. Αυτές οι παράμετροι λειτουργούν σε επίπεδο γραμματοσειράς και εφαρμόζονται σε όλο το κείμενο που σχεδιάζεται από το συγκεκριμένο Paint. Για ευέλικτη μορφοποίηση διαφορετικών τμημάτων της ίδιας γραμμής, χρησιμοποιήστε ξεχωριστά αντικείμενα Paint με διαφορετικές ρυθμίσεις ή εναλλάξτε τις παραμέτρους μεταξύ κλήσεων drawText.
| Μέθοδος | Σκοπός | Μονάδα μέτρησης |
|---|---|---|
| setTextSize | Μέγεθος γραμματοσειράς | px (pixel) |
| setTextAlign | Οριζόντια στοίχιση | LEFT, CENTER, RIGHT |
| setTypeface | Γραμματοσειρά | Typeface object |
| setUnderlineText | Υπογράμμιση | Boolean |
Shader — βασική κλάση για γέμισμα σχημάτων με gradient, bitmap υφές και σύνθετα. Μέσω της μεθόδου setShader μπορεί να οριστεί οποιαδήποτε από τις υποκλάσεις: LinearGradient, RadialGradient, SweepGradient, BitmapShader ή ComposeShader. Το Shader αντικαθιστά το χρώμα που ορίστηκε από το setColor και εφαρμόζεται σε όλα τα σχεδιασμένα στοιχεία.
LinearGradient δημιουργεί ομαλή μετάβαση μεταξύ δύο ή περισσότερων χρωμάτων κατά μήκος μιας ευθείας γραμμής. Ο κατασκευαστής δέχεται σημεία έναρξης και λήξης, έναν πίνακα χρωμάτων και τις θέσεις τους (λειτουργία πλακιδίου). Η λειτουργία πλακιδίου καθορίζει τη συμπεριφορά εκτός gradient: CLAMP (επανάληψη του τελευταίου χρώματος), MIRROR (κατοπτρισμός) ή REPEAT (επανάληψη). Το LinearGradient χρησιμοποιείται ενεργά για γεμίσματα φόντου και γραμμές προόδου.
RadialGradient δημιουργεί κυκλικό gradient από το κέντρο προς τις άκρες. Το κέντρο καθορίζεται από συντεταγμένες, η ακτίνα ορίζει τη ζώνη μετάβασης χρωμάτων. Η εμφάνιση του ακτινικού gradient θυμίζει φωτισμό από σημειακή πηγή — αυτό χρησιμοποιείται συχνά για προσομοίωση λάμψης κουμπιών και φωτισμού ενεργών στοιχείων.
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 που σχεδιάζει έναν κύκλο με γέμισμα gradient και λεζάντα κειμένου. Ο συνδυασμός 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("Gradient", 200f, 210f, textPaint)
}
}
Στον κώδικα χρησιμοποιούνται δύο ξεχωριστά αντικείμενα Paint: ένα για το γέμισμα του κύκλου με ακτινικό gradient, το δεύτερο για κείμενο με σκιά μέσω BlurMaskFilter. Αυτός ο διαχωρισμός επιτρέπει την ανεξάρτητη διαμόρφωση των παραμέτρων και αποφεύγει την επαναφορά της κατάστασης Paint μεταξύ σχεδίασης διαφορετικών τύπων στοιχείων. Για αύξηση της απόδοσης, και τα δύο Paint δημιουργούνται στον κατασκευαστή, όχι στο onDraw.
Κατά την κλιμάκωση σε συσκευές με διαφορετική πυκνότητα pixel, οι τιμές μεγέθους πρέπει να υπολογίζονται εκ νέου μέσω TypedValue.applyDimension. Χωρίς αυτό, το κείμενο και το gradient θα εμφανίζονται διαφορετικά σε οθόνες mdpi και xxxhdpi. Στο παράδειγμα, το μέγεθος κειμένου ορίζεται σε sp, το οποίο προσαρμόζεται αυτόματα στις συστημικές ρυθμίσεις μεγέθους γραμματοσειράς του χρήστη.
Συχνές ερωτήσεις
Canvas εκτελεί λειτουργίες σχεδίασης (drawCircle, drawLine), ενώ το Paint καθορίζει το στυλ — χρώμα, πάχος, γραμματοσειρά. Το Canvas δεν περιέχει ρυθμίσεις στυλ, επομένως χωρίς Paint καμία λειτουργία σχεδίασης δεν έχει οπτικό αποτέλεσμα.
Ναι, ένα αντικείμενο Paint μπορεί να επαναχρησιμοποιηθεί για πολλά σχήματα. Συνιστάται η δημιουργία ξεχωριστών Paint για διαφορετικούς τύπους στοιχείων (φόντο, κείμενο, περίγραμμα), αλλά όχι για κάθε σχήμα — αυτό μειώνει το φορτίο του garbage collector.
Η μέθοδος reset επαναφέρει το Paint σε κατάσταση ισοδύναμη με νέο instance. Εναλλακτικά, μπορεί να χρησιμοποιηθεί το set με σημαία, αλλά το reset είναι προτιμότερο για αναγνωσιμότητα κώδικα. Μετά την επαναφορά, όλες οι παράμετροι στυλ λαμβάνουν προεπιλεγμένες τιμές.
Η δημιουργία Paint εντός onDraw προκαλεί δέσμευση σε κάθε καρέ, οδηγώντας σε παγώματα GC. Όλα τα αντικείμενα Paint πρέπει να δημιουργούνται στον κατασκευαστή View. Η αλλαγή παραμέτρων στο onDraw μέσω setter είναι ασφαλής και δεν δημιουργεί νέα αντικείμενα.
Το κείμενο στο Android σχεδιάζεται πάντα με διάφανο φόντο. Η μέθοδος drawText εμφανίζει μόνο τα γλύφω, χωρίς ορθογώνιο φόντου. Αν χρειάζεται φόντο κάτω από το κείμενο, σχεδιάστε πρώτα ένα ορθογώνιο μέσω drawRoundRect με ξεχωριστό Paint και μετά το κείμενο.
Σύνοψη
Θα αναπτύξουμε μια εφαρμογή για κινητά έτοιμη για χρήση
Η IT Sectr δημιουργεί εφαρμογές iOS και Android για νεοφυείς επιχειρήσεις και επιχειρήσεις από το 2017. Θα σας συμβουλεύσουμε και θα προτείνουμε την καλύτερη λύση.
Διαβάστε επίσης