פסקת סגנון

בדף הזה מוסבר איך לעצב את הטקסט בפסקה. כדי להגדיר סגנון ברמת הפסקה, אפשר להגדיר פרמטרים כמו textAlign ו-lineHeight או להגדיר ParagraphStyle משלכם.

הגדרת יישור הטקסט

הפרמטר textAlign מאפשר להגדיר את היישור האופקי של הטקסט בתוך שטח הפנים של רכיב ה-Composable‏ Text.

כברירת מחדל, Text יבחר את יישור הטקסט הטבעי בהתאם לערך התוכן שלו:

  • הקצה השמאלי של מאגר Text לאלפבית משמאל לימין, כמו לטינית, קירילית או הנגול
  • הקצה הימני של מאגר Text לאלפבית שנכתב מימין לשמאל, כמו ערבית או עברית

@Composable
fun CenterText() {
    Text(
        "Hello World", textAlign = TextAlign.Center, modifier = Modifier.width(150.dp)
    )
}

המילים

אם רוצים להגדיר באופן ידני את יישור הטקסט של רכיב Text קומפוזבילי, עדיף להשתמש ב-TextAlign.Start וב-TextAlign.End במקום ב-TextAlign.Left וב-TextAlign.Right בהתאמה, כי הם פותרים את הבעיה בקצה הימני של הרכיב Text קומפוזבילי, בהתאם לכיוון הטקסט של השפה המועדפת. לדוגמה, TextAlign.End מיישר לצד ימין טקסט בצרפתית ולצד שמאל טקסט בערבית, אבל TextAlign.Right מיישר לצד ימין בלי קשר לאלפבית שבו משתמשים.

הוספת כמה סגנונות לפסקה

כדי להוסיף כמה סגנונות לפסקה, אפשר להשתמש ב-ParagraphStyle ב-AnnotatedString, שאפשר להוסיף לו הערות עם סגנונות של הערות שרירותיות. אחרי שחלק מהטקסט מסומן ב-ParagraphStyle, החלק הזה מופרד משאר הטקסט כאילו יש לו מעברי שורה בהתחלה ובסוף.

איך מוסיפים כמה סגנונות לטקסט

ל-AnnotatedString יש כלי ליצירת מניעת שגיאות הקלדה כדי שיהיה קל יותר ליצור: buildAnnotatedString. בקטע הקוד הבא, משתמשים ב-buildAnnotatedString כדי להגדיר את ParagraphStyle:

@Composable
fun ParagraphStyle() {
    Text(
        buildAnnotatedString {
            withStyle(style = ParagraphStyle(lineHeight = 30.sp)) {
                withStyle(style = SpanStyle(color = Color.Blue)) {
                    append("Hello\n")
                }
                withStyle(
                    style = SpanStyle(
                        fontWeight = FontWeight.Bold, color = Color.Red
                    )
                ) {
                    append("World\n")
                }
                append("Compose")
            }
        }
    )
}

שלוש פסקאות בשלושה סגנונות שונים: כחול, אדום ומודגש, ושחור רגיל

שינוי גובה השורה והמרווח הפנימי

includeFontPadding הוא מאפיין מדור קודם שמוסיף ריפוד נוסף על סמך מדדי הגופן בחלק העליון של השורה הראשונה ובחלק התחתון של השורה האחרונה של הטקסט. החל מגרסה 2024.01.01 של Compose BOM, הערך של includeFontPadding מוגדר כברירת מחדל ל-false, כך שפריסת הטקסט שמוגדרת כברירת מחדל תואמת יותר לכלי עיצוב נפוצים.

האפשרות להגדיר את lineHeight לא חדשה – היא זמינה מאז Android Q. אפשר להגדיר את lineHeight ל-Text באמצעות הפרמטר lineHeight, שמחלק את גובה השורה בכל שורת טקסט. אחר כך אפשר להשתמש ב-LineHeightStyle API החדש כדי להגדיר איך הטקסט הזה מיושר בתוך המרחב, ולהסיר רווחים לבנים.

כדי לשפר את הדיוק, מומלץ לשנות את lineHeight באמצעות יחידת הטקסט em (גודל גופן יחסי) במקום sp (פיקסלים מותאמים). למידע נוסף על בחירת יחידת טקסט מתאימה, ראו TextUnit.

תמונה שבה מוצג lineHeight כמידה שמבוססת על השורות שמעליו ומתחתיו.
איור 1. משתמשים באפשרויות "יישור" ו"חיתוך" כדי להתאים את הטקסט בתוך הקבוצה lineHeight, וחותכים רווחים מיותרים אם צריך.

Text(
    text = text,
    style = LocalTextStyle.current.merge(
        TextStyle(
            lineHeight = 2.5.em,
            platformStyle = PlatformTextStyle(
                includeFontPadding = false
            ),
            lineHeightStyle = LineHeightStyle(
                alignment = LineHeightStyle.Alignment.Center,
                trim = LineHeightStyle.Trim.None
            )
        )
    )
)

בנוסף להתאמה של lineHeight, עכשיו אפשר למרכז את הטקסט ולעצב אותו עוד יותר באמצעות הגדרות ב-API של LineHeightStyle: LineHeightStyle.Alignment ו-LineHeightStyle.Trim (צריך להגדיר את includeFontPadding ל-false כדי שהחיתוך יפעל). התכונות "יישור" ו"חיתוך" משתמשות במרווח שנמדד בין שורות הטקסט כדי לחלק אותו בצורה מתאימה יותר לכל השורות – כולל שורת טקסט אחת והשורה העליונה של גוש טקסט.

LineHeightStyle.Alignment מגדיר איך ליישר את השורה במרחב שנוצר על ידי גובה השורה. בכל שורה, אפשר ליישר את הטקסט למעלה, למטה, למרכז או באופן פרופורציונלי. LineHeightStyle.Trim מאפשר להשאיר או להסיר את הרווח הנוסף בחלק העליון של השורה הראשונה ובחלק התחתון של השורה האחרונה בטקסט, שנוצר מכל שינוי של lineHeight ויישור. בדוגמאות הבאות אפשר לראות איך טקסט בכמה שורות נראה עם הגדרות שונות של LineHeightStyle.Trim כשהיישור הוא למרכז (LineHeightStyle.Alignment.Center).

תמונה שמדגימה את LineHeightStyle.Trim.None תמונה שמדגימה את LineHeightStyle.Trim.Both
LineHeightStyle.Trim.None LineHeightStyle.Trim.Both
תמונה שמדגימה את LineHeightStyle.Trim.FirstLineTop תמונה שמדגימה את LineHeightStyle.Trim.LastLineBottom
LineHeightStyle.Trim.FirstLineTop LineHeightStyle.Trim.LastLineBottom

בפוסט בבלוג Fixing Font Padding in Compose Text מוסבר בהרחבה על ההקשר של השינוי הזה, איך includeFontPadding פעל במערכת View והשינויים שבוצעו ב-Compose ובממשקי ה-API החדשים של LineHeightStyle.

הוספת מעברי שורה

ה-API של LineBreak מגדיר את הקריטריונים שלפיהם הטקסט מפוצל לכמה שורות. אתם יכולים לציין את סוג מעבר השורה שאתם רוצים בבלוק TextStyle של ה-composable‏ Text. אלה סוגי מעברי השורות המוגדרים מראש:

  • Simple — שבירת שורה בסיסית ומהירה. מומלץ לשדות להזנת טקסט.
  • Heading — מעבר שורה עם כללי מעבר שורה פחות מחמירים. מומלץ לטקסט קצר, כמו כותרות.
  • Paragraph — מעבר שורה איטי יותר ואיכותי יותר, לשיפור הקריאוּת. מומלץ לכמויות גדולות יותר של טקסט, כמו פסקאות.

קטע הקוד הבא משתמש גם ב-Simple וגם ב-Paragraph כדי לציין את ההתנהגות של מעבר השורה בגוש טקסט ארוך:

TextSample(
    samples = mapOf(
        "Simple" to {
            Text(
                text = SAMPLE_LONG_TEXT,
                modifier = Modifier
                    .width(130.dp)
                    .border(BorderStroke(1.dp, Color.Gray)),
                fontSize = 14.sp,
                style = TextStyle.Default.copy(
                    lineBreak = LineBreak.Simple
                )
            )
        },
        "Paragraph" to {
            Text(
                text = SAMPLE_LONG_TEXT,
                modifier = Modifier
                    .width(130.dp)
                    .border(BorderStroke(1.dp, Color.Gray)),
                fontSize = 14.sp,
                style = TextStyle.Default.copy(
                    lineBreak = LineBreak.Paragraph
                )
            )
        }
    )
)

בלוק טקסט שמציג אסטרטגיה פשוטה של מעבר שורה לעומת בלוק טקסט עם אסטרטגיית מעבר שורה שמותאמת לפסקה. בגוש הטקסט עם האסטרטגיה הפשוטה של מעבר שורה, יש יותר הבדלים באורכי השורות.
איור 1. בלוק טקסט עם אסטרטגיית מעבר שורה פשוטה (למעלה) לעומת בלוק טקסט עם מעבר שורה שמותאם לפסקה (למטה).

בפלט שלמעלה, שימו לב שההתנהגות של מעבר השורה ב-Paragraph מפיקה תוצאה מאוזנת יותר מבחינה חזותית מאשר מעבר השורה ב-Simple.

התאמה אישית של מעברי שורות

אפשר גם ליצור הגדרות אישיות של LineBreak באמצעות הפרמטר Strategy. הערך Strategy יכול להיות כל אחת מהאפשרויות הבאות:

  • Balanced — ניסיון לאזן את אורך השורות של הטקסט, וגם להחיל חלוקת מילים אוטומטית אם היא מופעלת. מומלץ למסכים קטנים, כמו שעונים, כדי להציג כמה שיותר טקסט.
  • HighQuality — אופטימיזציה של פסקה לטקסט קריא יותר, כולל הוספת מקפים אם האפשרות מופעלת. (צריך להיות ברירת המחדל לכל מה שהוא לא Balanced או Simple).
  • Simple – אסטרטגיה בסיסית ומהירה. אם המדיניות מופעלת, הוספת מקפים נעשית רק למילים שלא נכנסות בשורה שלמה בפני עצמן. התכונה הזו שימושית כשעורכים טקסט, כדי למנוע שינוי של המיקום בזמן ההקלדה.

קטע הקוד הבא מראה את ההבדל בין פסקה עם הגדרות ברירת מחדל לבין פסקה שעברה אופטימיזציה למסכים קטנים באמצעות אסטרטגיית מעבר השורה Balanced:

TextSample(
    samples = mapOf(
        "Balanced" to {
            val smallScreenAdaptedParagraph =
                LineBreak.Paragraph.copy(strategy = LineBreak.Strategy.Balanced)
            Text(
                text = SAMPLE_LONG_TEXT,
                modifier = Modifier
                    .width(200.dp)
                    .border(BorderStroke(1.dp, Color.Gray)),
                fontSize = 14.sp,
                style = TextStyle.Default.copy(
                    lineBreak = smallScreenAdaptedParagraph
                )
            )
        },
        "Default" to {
            Text(
                text = SAMPLE_LONG_TEXT,
                modifier = Modifier
                    .width(200.dp)
                    .border(BorderStroke(1.dp, Color.Gray)),
                fontSize = 14.sp,
                style = TextStyle.Default
            )
        }
    )
)

פסקה עם אסטרטגיית מעבר שורה מאוזנת ופסקה
  שעוצבה ללא אסטרטגיה. בפסקה עם אסטרטגיית מעבר השורה המאוזנת,
  אורכי השורות עקביים יותר מאשר בברירת המחדל.
איור 2. פסקה שמעוצבת עם אסטרטגיית מעבר שורה של Balanced (למעלה) לעומת פסקה שמעוצבת בלי אסטרטגיית מעבר שורה.

שיקולים לגבי CJK

אפשר גם להתאים אישית את LineBreak באמצעות ממשקי ה-API‏ Strictness ו-WordBreak, שתוכננו במיוחד לשפות CJK. יכול להיות שלא תמיד תראו את ההשפעות של ממשקי ה-API האלה בשפות שאינן סינית, יפנית וקוריאנית. באופן כללי, הכללים של מעברי השורות מוגדרים לפי הלוקאל.

המאפיין Strictness מתאר את מידת ההקפדה על מעבר השורה, באמצעות המאפיינים הבאים:

  • ‫Default – כללי ברירת המחדל להוספת מעברי שורה בהתאם להגדרות המקומיות. יכול להתאים ל-Normal או ל-Strict.
  • ‫Loose – הכללים הכי פחות מגבילים. מתאים לשורות קצרות.
  • Normal – הכללים הנפוצים ביותר למעבר שורה.
  • ‫Strict – הכללים המחמירים ביותר למעבר שורה.

WordBreak מגדיר איך להוסיף מעברי שורה בתוך מילים עם המאפיינים הבאים:

  • ‫Default – כללי ברירת המחדל להוספת מעברי שורה בהתאם להגדרות המקומיות.
  • Phrase — מעברי השורה מבוססים על ביטויים.

בקטע הקוד הבא נעשה שימוש בהגדרה Strict למידת ההקפדה ובהגדרה Phrase לחלוקת מילים בטקסט ביפנית:

val customTitleLineBreak = LineBreak(
    strategy = LineBreak.Strategy.HighQuality,
    strictness = LineBreak.Strictness.Strict,
    wordBreak = LineBreak.WordBreak.Phrase
)
Text(
    text = "あなたに寄り添う最先端のテクノロジー。",
    modifier = Modifier.width(250.dp),
    fontSize = 14.sp,
    style = TextStyle.Default.copy(
        lineBreak = customTitleLineBreak
    )
)

טקסט ביפנית עם הגדרות Strictness ו-WordBreak לעומת טקסט ברירת מחדל.
איור 3. טקסט שמעוצב עם ההגדרות Strictness ו-WordBreak (למעלה) לעומת טקסט שמעוצב רק עם LineBreak.Heading (למטה).

הוספת מקפים בטקסט שמפוצל בין שורות

באמצעות ה-API של Hyphens אתם יכולים להוסיף לאפליקציה תמיכה בהוספת מקפים, כלומר הוספה של סימן פיסוק דמוי מקף כדי לציין שמילה מחולקת בין שורות טקסט. כשההגדרה הזו מופעלת, המערכת מוסיפה מקפים בין ההברות של מילה בנקודות המתאימות.

כברירת מחדל, חלוקת מילים לא מופעלת. כדי להפעיל חלוקת מילים, מוסיפים את Hyphens.Auto כפרמטר בבלוק TextStyle:

TextSample(
    samples = mapOf(
        "Hyphens - None" to {
            Text(
                text = SAMPLE_LONG_TEXT,
                modifier = Modifier
                    .width(130.dp)
                    .border(BorderStroke(1.dp, Color.Gray)),
                fontSize = 14.sp,
                style = TextStyle.Default.copy(
                    lineBreak = LineBreak.Paragraph,
                    hyphens = Hyphens.None
                )
            )
        },
        "Hyphens - Auto" to {
            Text(
                text = SAMPLE_LONG_TEXT,
                modifier = Modifier
                    .width(130.dp)
                    .border(BorderStroke(1.dp, Color.Gray)),
                fontSize = 14.sp,
                style = TextStyle.Default.copy(
                    lineBreak = LineBreak.Paragraph,
                    hyphens = Hyphens.Auto
                )
            )
        }
    )
)

פסקה בלי חלוקת מילים ופסקה עם חלוקת מילים.
  כשהאפשרות הזו מופעלת, המילה מפוצלת לשתי שורות עם מקף.
איור 4. פסקה בלי מיקוף (למעלה) לעומת פסקה עם מיקוף (למטה).

כשהתכונה מופעלת, המילים יחולקו רק בתנאים הבאים:

  • מילה לא נכנסת בשורה. אם משתמשים באסטרטגיית מעבר שורה Simple, המקף במילה מופיע רק אם השורה קצרה יותר מהמילה הבודדת.
  • הגדרתם במכשיר את השפה והאזור המתאימים, כי המערכת משתמשת במילונים כדי לקבוע את מיקום המקפים.