sp — Scale-independent Pixels, μονάδα μέτρησης κειμένου στο Android που λαμβάνει υπόψη τις ρυθμίσεις μεγέθους γραμματοσειράς στη συσκευή. Σε αντίθεση με το dp, το sp κλιμακώνεται μαζί με το μέγεθος γραμματοσειράς συστήματος, εξασφαλίζοντας προσβασιμότητα διεπαφών. Το άρθρο εξηγεί τη διαφορά μεταξύ sp και dp, δείχνει τη ρύθμιση textSize σε XML και Kotlin και αποκαλύπτει τις βέλτιστες πρακτικές εργασίας με τυπογραφία στο Android.
Κύρια Σημεία
sp (scale-independent pixel) — μονάδα μέτρησης μεγέθους γραμματοσειράς στο Android που κλιμακώνεται αυτόματα σύμφωνα με τις ρυθμίσεις συστήματος του χρήστη. Όταν ο κάτοχος της συσκευής αυξάνει το μέγεθος γραμματοσειράς στις ρυθμίσεις, όλα τα στοιχεία με τιμές sp μεγαλώνουν αναλογικά. Αυτό εξασφαλίζει προσβασιμότητα της διεπαφής για άτομα με αδύναμη όραση.
Βασική αναλογία: 1 sp = 1 dp σε τυπική κλίμακα γραμματοσειράς 1.0 (normal). Εάν ο χρήστης ορίσει γραμματοσειρά Large (1.15×), 16 sp μετατρέπονται σε 18.4 φυσικά pixel. Σε μέγεθος γραμματοσειράς Small (0.85×), τα ίδια 16 sp γίνονται 13.6 px. Ο μηχανισμός κλιμάκωσης διαχειρίζεται μέσω Settings.System.FONT_SCALE σε επίπεδο Android Framework.
Σύμφωνα με το Google Material Design Guidelines, το κείμενο πρέπει να ορίζεται αποκλειστικά σε sp. Εξαίρεση — σταθερές ετικέτες σε στοιχεία όπου το μέγεθος είναι κρίσιμο για τη διάταξη (π.χ. κείμενο μέσα σε κουμπιά σταθερού ύψους). Σε τέτοιες περιπτώσεις συνιστάται η χρήση dp με χειροκίνητο έλεγχο προσβασιμότητας.
Η διαφορά μεταξύ sp και dp — ένα από τα πιο συνηθισμένα θέματα ερωτήσεων σε συνεντεύξεις Android-developer και σε πραγματικά code review. Και οι δύο μονάδες συνδέονται με το density-independent pixel (160 dpi = 1 dp = 1 px σε οθόνη mdpi), αλλά συμπεριφέρονται διαφορετικά όταν αλλάζει το μέγεθος γραμματοσειράς συστήματος.
| Χαρακτηριστικό | sp | dp |
|---|---|---|
| Σκοπός | Μέγεθος κειμένου | Διαστάσεις στοιχείων, αποστάσεις, πλάτος, ύψος |
| Κλιμάκωση με γραμματοσειρά | Ναι (scale factor) | Όχι |
| Κλιμάκωση με πυκνότητα | Ναι | Ναι |
| API για ρύθμιση | android:textSize | android:layout_width, layout_height, padding, margin |
| Material Design Token | typescale | spacing, sizing |
Στην πράξη λάθος — η χρήση dp για κείμενο. Εάν το κείμενο οριστεί σε dp, δεν κλιμακώνεται όταν αυξάνεται η γραμματοσειρά, καθιστώντας τη διεπαφή μη προσβάσιμη για χρήστες με αδύναμη όραση. Το αντίστροφο λάθος — χρήση sp για ύψος κουμπιού ή αποστάσεις: όταν αυξάνεται η γραμματοσειρά, το κουμπί μπορεί να «φουσκώσει», χαλώντας τη διάταξη.
Η κλιμάκωση sp υλοποιείται σε επίπεδο Android Framework στην κλάση TypedValue. Ο τύπος υπολογισμού: sp = dp × scaledDensity, όπου scaledDensity είναι ο συντελεστής κλίμακας που λαμβάνει υπόψη τόσο την πυκνότητα οθόνης όσο και τη ρύθμιση γραμματοσειράς του χρήστη.
// Προγραμματική λήψη scaledDensity σε Kotlin
val scaledDensity = with(context.resources) {
displayMetrics.scaledDensity
}
// Μετατροπή sp σε px
fun spToPx(sp: Float, context: Context): Float {
return TypedValue.applyDimension(
TypedValue.COMPLEX_UNIT_SP,
sp,
context.resources.displayMetrics
)
}
// Μετατροπή px σε sp
fun pxToSp(px: Float, context: Context): Float {
return px / context.resources.displayMetrics.scaledDensity
}Η μέθοδος TypedValue.applyDimension — ο μόνος σωστός τρόπος μετατροπής sp σε pixel κατά τον χρόνο εκτέλεσης. Ο άμεσος πολλαπλασιασμός με scaledDensity είναι λιγότερο αξιόπιστος επειδή δεν χειρίζεται ακραίες περιπτώσεις (μηδενικές τιμές, υπερχείλιση). Το scaledDensity αλλάζει όταν αλλάζουν οι ρυθμίσεις γραμματοσειράς μέσω Settings > Display > Font size.
Το Android παρέχει πέντε προρυθμισμένα επίπεδα κλίμακας γραμματοσειράς: Small (0.85×), Default (1.0×), Large (1.15×), Largest (1.3×) και ένα επιπλέον επίπεδο Very Large (>1.3×) στο Android 14+. Οι κατασκευαστές συσκευών (Samsung, Xiaomi) προσθέτουν δικά τους επίπεδα — έως 2.0×. Το ελάχιστο μέγεθος κειμένου σε sp δεν εγγυάται ποτέ σταθερό αριθμό pixel.
Σε XML το sp χρησιμοποιείται αποκλειστικά στο χαρακτηριστικό android:textSize. Όλες οι άλλες διαστάσεις — width, height, padding, margin, elevation — ορίζονται σε dp. Ο κανόνας είναι απλός: αν ένα στοιχείο εμφανίζει κείμενο — το μέγεθός του σε sp, αν ένα στοιχείο ορίζει γεωμετρία — το μέγεθος σε dp.
<!-- Διάταξη TextView με textSize σε sp -->
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="@string/hello"
android:textSize="16sp"
android:padding="12dp"
android:lineSpacingExtra="4dp" />
<!-- Χρήση πόρων dimens -->
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textSize="@dimen/text_body_large" />Συνιστάται η εξαγωγή μεγεθών κειμένου στο αρχείο dimens.xml. Αυτό απλοποιεί τη συντήρηση της τυπογραφίας, επιτρέπει την παράκαμψη μεγεθών για διαφορετικές διαμορφώσεις οθόνης και εξασφαλίζει ομοιομορφία σε ολόκληρη την εφαρμογή.
<!-- res/values/dimens.xml -->
<resources>
<!-- Material Design Type Scale -->
<dimen name="text_display_large">34sp</dimen>
<dimen name="text_display_medium">28sp</dimen>
<dimen name="text_headline_large">24sp</dimen>
<dimen name="text_headline_medium">20sp</dimen>
<dimen name="text_title_large">18sp</dimen>
<dimen name="text_body_large">16sp</dimen>
<dimen name="text_body_medium">14sp</dimen>
<dimen name="text_label_large">14sp</dimen>
<dimen name="text_label_small">11sp</dimen>
</resources>Το Material Design Type Scale περιλαμβάνει 13 επίπεδα μεγεθών — από 11sp για μικρές ετικέτες έως 57sp για μεγάλες επικεφαλίδες οθόνης. Τα έργα Android συνήθως χρησιμοποιούν 8–10 επίπεδα. Όλες οι τιμές πρέπει να είναι πολλαπλάσια του 1sp — οι κλασματικές τιμές (15.5sp) υποβαθμίζουν την απόδοση λόγω υποεικονοστοιχειακής τοποθέτησης.
Στη σύγχρονη ανάπτυξη Android, το κείμενο σπάνια ορίζεται άμεσα μέσω textSize σε sp. Αντί αυτού, χρησιμοποιείται το σύστημα MaterialTheme.typography, όπου κάθε στυλ είναι προκαθορισμένο και περιλαμβάνει μέγεθος, βάρος, διάστιχο και letter-spacing.
// Προσαρμοσμένη τυπογραφία μέσω Typography API
val AppTypography = Typography(
displayLarge = TextStyle(
fontWeight = FontWeight.Normal,
fontSize = 34.sp,
lineHeight = 40.sp,
letterSpacing = 0.sp
),
headlineLarge = TextStyle(
fontWeight = FontWeight.SemiBold,
fontSize = 24.sp,
lineHeight = 32.sp
),
titleLarge = TextStyle(
fontWeight = FontWeight.Medium,
fontSize = 18.sp,
lineHeight = 24.sp
),
bodyLarge = TextStyle(
fontWeight = FontWeight.Normal,
fontSize = 16.sp,
lineHeight = 24.sp,
letterSpacing = 0.5.sp
),
labelSmall = TextStyle(
fontWeight = FontWeight.Medium,
fontSize = 11.sp,
lineHeight = 16.sp,
letterSpacing = 0.5.sp
)
)Η συνάρτηση επέκτασης .sp στο Jetpack Compose μεταφράζεται αυτόματα σε scale-independent pixels. Όταν αλλάζει το μέγεθος γραμματοσειράς συστήματος, το Compose υπολογίζει ξανά τα fontSize, lineHeight και spacing σύμφωνα με το νέο scaledDensity. Το TextUnit (η κλάση που αντιπροσωπεύει το sp) εγγυάται ότι το κείμενο κλιμακώνεται, ενώ οι αποστάσεις — όχι.
Στο Jetpack Compose το sp αντιπροσωπεύεται από τον τύπο TextUnit, ο οποίος δεν μπορεί να χρησιμοποιηθεί κατά λάθος για διαστάσεις στοιχείων. Ο μεταγλωττιστής Kotlin δίνει σφάλμα αν το TextUnit περαστεί εκεί όπου αναμένεται Dp. Αυτό εξαλείφει μια ολόκληρη κατηγορία σφαλμάτων που σχετίζονται με εσφαλμένη κλιμάκωση.
// TextUnit στο Compose — ασφαλής εργασία με sp
@Composable
fun ArticleCard(title: String, description: String) {
Card(modifier = Modifier
.fillMaxWidth()
.padding(16.dp)
) {
Text(
text = title,
style = MaterialTheme.typography.titleLarge
)
Spacer(modifier = Modifier.height(8.dp))
Text(
text = description,
style = MaterialTheme.typography.bodyMedium
)
}
}
// Ρητή ρύθμιση fontSize σε sp
Text(
text = "Προσαρμοσμένο μέγεθος",
fontSize = 20.sp,
fontWeight = FontWeight.Bold,
color = MaterialTheme.colorScheme.primary
)Στο Compose δεν υπάρχει άμεσο ισοδύναμο του χαρακτηριστικού XML android:textSize — το μέγεθος κειμένου ορίζεται μέσω TextStyle.fontSize. Το σύστημα MaterialTheme.typography παρέχει προκαθορισμένα στυλ που αντιστοιχούν στο Material Design Type Scale. Αν χρειαστεί προσαρμοσμένο μέγεθος, χρησιμοποιείται το literal 20.sp — η γλώσσα εγγυάται ότι είναι TextUnit, όχι Dp.
Η σωστή χρήση του sp — η βάση μιας προσβάσιμης εφαρμογής Android. Παρακάτω συγκεντρώνονται κανόνες βασισμένοι στις συστάσεις του Google Material Design και του Android Developers Guide.
Ο κύριος κανόνας προσβασιμότητας: ο χρήστης πρέπει να έχει τη δυνατότητα να αυξήσει τη γραμματοσειρά χωρίς απώλεια λειτουργικότητας. Εάν η εφαρμογή λειτουργεί σωστά σε κλίμακα γραμματοσειράς 1.3×, θα περάσει τα βασικά τεστ προσβασιμότητας. Το Google Play μπορεί να απορρίψει την εφαρμογή αν το textSize έχει οριστεί σε dp και η διεπαφή δεν κλιμακώνεται.
Συχνές Ερωτήσεις
sp (scale-independent pixel) κλιμακώνεται όταν αλλάζει το μέγεθος γραμματοσειράς συστήματος, ενώ το dp — όχι. το sp χρησιμοποιείται μόνο για κείμενο, το dp — για όλες τις άλλες διαστάσεις στοιχείων. Συντελεστής μετατροπής: sp = dp × FONT_SCALE.
Όχι. Οι αποστάσεις, το ύψος κουμπιών, το πλάτος καρτών πρέπει να ορίζονται σε dp. Η χρήση sp για αποστάσεις οδηγεί σε αφύσικη ανάπτυξη στοιχείων όταν αυξάνεται η γραμματοσειρά και μπορεί να βγουν εκτός ορίων οθόνης.
Ανοίξτε Settings > Display > Font size και ορίστε τη μέγιστη τιμή (Largest). Εκκινήστε την εφαρμογή και ελέγξτε ότι όλο το κείμενο είναι ευανάγνωστο, τα στοιχεία δεν επικαλύπτονται και τα κουμπιά δεν βγαίνουν εκτός ορίων οθόνης. Για αυτοματοποίηση, χρησιμοποιήστε Espresso με UiAutomator.
Το Material Design συνιστά ελάχιστο μέγεθος 11sp για labelSmall. Για κύριο κείμενο — από 14sp (bodyMedium) έως 16sp (bodyLarge). Μεγέθη μικρότερα από 11sp δεν συνιστώνται, καθώς γίνονται δυσανάγνωστα σε συσκευές με υψηλή πυκνότητα pixel.
Το κείμενο θα εμφανίζεται σε σταθερό μέγεθος ανεξάρτητα από τις ρυθμίσεις γραμματοσειράς συστήματος. Οι χρήστες με μεγεθυμένη γραμματοσειρά δεν θα μπορούν να διαβάσουν άνετα τέτοιο κείμενο. Αυτό παραβιάζει τις απαιτήσεις προσβασιμότητας WCAG και μπορεί να οδηγήσει σε απόρριψη της εφαρμογής στο Google Play.
Περίληψη
Θα αναπτύξουμε μια εφαρμογή για κινητά έτοιμη για χρήση
Η IT Sectr δημιουργεί εφαρμογές iOS και Android για νεοφυείς επιχειρήσεις και επιχειρήσεις από το 2017. Θα σας συμβουλεύσουμε και θα προτείνουμε την καλύτερη λύση.
Διαβάστε επίσης