פסקת סגנון

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

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

הפרמטר textAlign מאפשר להגדיר את היישור האופקי של הטקסט בתוך אזור שאפשר להוסיף לו רכיבים 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 יש לו builder בטוח לטיפוסים כדי להקל על יצירת: 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, עכשיו אפשר למרכז את הטקסט ולשנות את הסגנון שלו באמצעות הגדרות עם LineHeightStyle API: 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

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

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

ממשק ה-API‏ LineBreak מגדיר את הקריטריונים שלפיהם הטקסט מפולג לכמה שורות. אפשר לציין את סוג מעברי השורה שרוצים להגדיר בבלוק TextStyle של רכיב ה-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 line-breaking:

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 האלה בשפות שאינן CJK. באופן כללי, כללי מעבר השורה מוגדרים על סמך הלוקאל.

המאפיינים הבאים מתארים את רמת ההקפדה על מעברי שורה ב-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 מעבר שורה, המילה תופרד באמצעות מקף רק אם השורה קצרה יותר מהמילה.
  • הלוקאל המתאים מוגדר במכשיר, כי המקפים המתאימים נקבעים באמצעות מילונים שקיימים במערכת.