Styl akapitu

Na tej stronie opisujemy, jak dostosować styl tekstu akapitu. Aby ustawić stylizację na poziomie akapitu, możesz skonfigurować parametry takie jak textAlign i lineHeight lub zdefiniować własny parametr ParagraphStyle.

Ustawianie wyrównania tekstu

Parametr textAlign umożliwia ustawienie poziomego wyrównania tekstu w powierzchni Text.

Domyślnie Text wybiera naturalne wyrównanie tekstu w zależności od jego wartości treści:

  • Lewa krawędź kontenera Text w przypadku alfabetów pisanych od lewej do prawej, takich jak alfabet łaciński, cyrylica czy hangul
  • Prawa krawędź kontenera Text w przypadku alfabetów zapisywanych od prawej do lewej, takich jak arabski czy hebrajski

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

Słowa

Jeśli chcesz ręcznie ustawić wyrównanie tekstu w komponowalnym Text, użyj funkcji TextAlign.StartTextAlign.End zamiast funkcji TextAlign.LeftTextAlign.Right, ponieważ te pierwsze dają lepszy efekt w przypadku prawej krawędzi kompozytowanego elementu Text w zależności od preferowanej orientacji tekstu. Na przykład TextAlign.End jest wyrównywane po prawej stronie w przypadku tekstu francuskiego i po lewej w przypadku tekstu arabskiego, ale TextAlign.Right jest wyrównywane po prawej stronie niezależnie od użytego alfabetu.

Dodawanie wielu stylów w akapicie

Aby dodać wiele stylów w akapicie, możesz użyć ParagraphStyleAnnotatedString, który może być opatrzony adnotacjami o dowolnym stylu. Gdy część tekstu zostanie oznaczona symbolem ParagraphStyle, zostanie oddzielona od reszty tekstu tak, jakby miała spacje na początku i na końcu.

Więcej informacji o dodawaniu wielu stylów w tekście znajdziesz w artykule Dodawanie wielu stylów w tekście.

AnnotatedString ma kreator zapewniający zgodność z typem, który ułatwia tworzenie: buildAnnotatedString. Ten fragment kodu używa parametru buildAnnotatedString do ustawienia 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")
            }
        }
    )
}

Trzy akapity w 3 różnych stylach: niebieski, czerwony i pogrubiony oraz zwykły czarny

Dostosowywanie wysokości wiersza i wypełniania

includeFontPadding to starsza właściwość, która dodaje dodatkowe wypełnienie na podstawie danych dotyczących czcionki u góry pierwszego wiersza i u dołu ostatniego wiersza tekstu. Od wersji 2024.01.01 pakietu Compose BOM parametr includeFontPadding jest domyślnie ustawiony na false, co sprawia, że domyślny układ tekstu jest bardziej zgodny ze standardowymi narzędziami do projektowania.

Możliwość konfigurowania lineHeight nie jest nowa – jest dostępna od Androida Q. Możesz skonfigurować lineHeight dla Text za pomocą parametru lineHeight, który rozkłada wysokość linii na każdą linię tekstu. Następnie możesz użyć nowego pola LineHeightStyle API, aby dostosować sposób wyrównania tekstu w pokoju i usunąć spacje.

Aby zwiększyć dokładność, możesz dostosować wartość lineHeight za pomocą jednostki tekstowej „em” (względny rozmiar czcionki) zamiast „sp” (skalowane piksele). Więcej informacji o wybieraniu odpowiedniej jednostki tekstu znajdziesz w artykule TextUnit.

Obraz przedstawiający wysokość elementu lineHeight jako pomiar w oparciu o linie bezpośrednio nad i pod spodem.
Rysunek 1. Użyj opcji Wyrównanie i Przytnij, aby dostosować tekst w zestawie lineHeight i w razie potrzeby przyciąć dodatkową spację.

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
            )
        )
    )
)

Oprócz dostosowywania lineHeight możesz teraz dodatkowo wyśrodkować tekst i nadać mu styl za pomocą konfiguracji z LineHeightStyle eksperymentalnym interfejsem API: LineHeightStyle.Alignment i LineHeightStyle.Trim (aby funkcja Trim działała, includeFontPadding musi być ustawiony na false). Wyrównanie i przycięcie korzystają z mierzonego odstępu między wierszami tekstu, aby lepiej rozmieścić tekst na wszystkich wierszach, w tym na pojedynczym wierszu tekstu i wierszu na górze bloku tekstu.

LineHeightStyle.Alignment określa, jak wyrównać wiersz w przestrzeni zapewnionej przez wysokość wiersza. W każdym wierszu możesz go wyrównać do góry, na dole, do środka lub proporcjonalnie. LineHeightStyle.Trim pozwala następnie opuścić lub usunąć dodatkową przestrzeń u góry pierwszego wiersza i na dole ostatniego wiersza tekstu, wygenerowaną na podstawie wszystkich dostosowań lineHeight i wyrównania. Poniższe przykłady pokazują, jak wygląda tekst wielowierszowy w różnych konfiguracjach LineHeightStyle.Trim, gdy wyrównanie jest ustawione na środku (LineHeightStyle.Alignment.Center).

Obraz pokazujący styl LineHeightStyle.Trim.None Obraz przedstawiający element LineHeightStyle.Przytnij.Both
LineHeightStyle.Trim.None LineHeightStyle.Trim.Both
Ilustracja pokazująca styl LineHeightStyle.Trim.FirstLineTop Obraz przedstawiający element LineHeightStyle.Przytnij.LastLinebottom
LineHeightStyle.Trim.FirstLineTop LineHeightStyle.Trim.LastLineBottom

Więcej informacji o kontekście tej zmiany, działaniu funkcji includeFontPadding w systemie View oraz zmianach wprowadzonych w komponencie Compose i nowych interfejsach API LineHeightStyle znajdziesz w poście na blogu Poprawki w odstępach między znakami w komponencie Compose.

Wstawianie podziałów wiersza

Interfejs API LineBreak definiuje kryteria, według których tekst jest dzielony na kilka wierszy. W bloku TextStyle w komponowalnym elemencie Text możesz określić, jaki typ dzielenia wiersza chcesz zastosować. Dostępne wstępnie typy dzielenia wiersza:

  • Simple – szybkie, podstawowe przerywanie linii. Zalecane w przypadku pól do wprowadzania tekstu.
  • Heading – przerywanie wiersza z mniej rygorystycznymi zasadami. Zalecany w przypadku krótkich tekstów, np. tytułów.
  • Paragraph – wolniejsze, wyższej jakości dzielenie wierszy w celu poprawy czytelności. Zalecane w przypadku większych ilości tekstu, np. akapitów.

Ten fragment kodu używa Simple i Paragraph do określenia sposobu podziału wierszy w długim bloku tekstu:

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
                )
            )
        }
    )
)

Blok tekstu pokazujący prostą strategię dzielenia tekstu na linie w porównaniu z blokiem tekstu z optymalizacją podziału na akapity. Blok tekstu z prostą strategią dzielenia wierszy ma większą zmienność długości wierszy.
Rysunek 1. Blok tekstu z prostą strategią dzielenia wierszy (u góry) w porównaniu z blokiem tekstu z optymalizacją dzielenia wierszy w paragrafach (u dołu).

W powyższym wyjściu widać, że zachowanie Paragraph w przypadku przełamania wiersza zapewnia bardziej zrównoważony wizualnie wynik niż zachowanie Simple.

Dostosuj podziały wierszy

Możesz też utworzyć własną konfigurację LineBreak za pomocą parametru Strategy. Strategy może być dowolnym z tych elementów:

  • Balanced – próbuje zrównoważyć długości wierszy tekstu z zastosowaniem automatycznego łącznika, jeśli jest włączone. Zaleca się używanie go na małych ekranach, takich jak zegarki, aby zmaksymalizować wyświetlany tekst.
  • HighQuality – optymalizuje akapit, by zwiększyć czytelność tekstu (także łącznik, jeśli jest włączony). (powinno być domyślne dla wszystkich wartości, które nie są Balanced ani Simple).
  • Simple – podstawowa, szybka strategia. Jeśli ta opcja jest włączona, podział na sylaby jest stosowany tylko w przypadku słów, które nie mieszczą się w całym wierszu. Przydatne podczas edytowania tekstu, aby uniknąć zmiany pozycji podczas pisania.

Ten fragment kodu pokazuje różnicę między akapitem z ustawieniami domyślnymi a akapitem zoptymalizowanym pod kątem małych ekranów przy użyciu strategii podziału wierszy 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
            )
        }
    )
)

Akapit ze strategią równomiernego rozmieszczania znaków końca wiersza oraz akapit sformatowany bez strategii. Akapit ze strategią łamania wierszy ma bardziej stabilną długość wierszy niż domyślna.
Rysunek 2. Akapit sformatowany zgodnie ze strategią podziału wiersza Balanced (u góry) i akapitów sformatowanych bez tej strategii.

Uwagi dotyczące CJK

Możesz też dostosować LineBreak za pomocą interfejsów API Strictness i WordBreak, które zostały zaprojektowane specjalnie do obsługi języków CJK. Efekty tych interfejsów API mogą nie być widoczne w językach innych niż CJK. Ogólnie reguły dzielenia linii są definiowane na podstawie lokalizacji.

Strictness określa rygoryzm rozbijania wiersza z tymi właściwościami:

  • Default – domyślne reguły naruszenia dotyczące danego ustawienia regionalnego. Może odpowiadać wartości Normal lub Strict.
  • Loose – zasady najmniej restrykcyjne. Odpowiednie do krótkich linii.
  • Normal – najczęstsze reguły dotyczące dzielenia wyrazów.
  • Strict – najsurowsze reguły dotyczące dzielenia wierszy.

WordBreak określa, jak w słowie mają być wstawiane znaki końca wiersza. Właściwości:

  • Default – domyślne reguły naruszenia dotyczące danego ustawienia regionalnego.
  • Phrase – podział wierszy opiera się na wyrażeniach.

Ten fragment kodu używa w przypadku tekstu japońskiego ustawień Strict (rygor) i Phrase (podział na słowa):

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
    )
)

Tekst japoński z ustawieniami Ścisłości i Podziału słów w porównaniu z tekstem domyślnym.
Rysunek 3. Tekst sformatowany z ustawieniami Strictness i WordBreak (u góry) a tekst sformatowany tylko przy użyciu LineBreak.Heading (u dołu).

Przecinek w tekście podzielonym na linie

Interfejs API Hyphens umożliwia dodanie do aplikacji obsługi dzielenia wyrazów. Dzielenie wyrazów polega na wstawianiu znaku interpunkcyjnego w postaci myślnika, aby wskazać, że wyraz jest podzielony na 2 wiersze tekstu. Gdy ta opcja jest włączona, w odpowiednich miejscach w słowie dodawane są łamań.

Domyślnie dzielenie wyrazów nie jest włączone. Aby włączyć dzielenie wyrazów, dodaj parametr Hyphens.Auto w bloku 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
                )
            )
        }
    )
)

akapitu bez myślnika i akapitu z włączonym dzieleniem.
  Gdy włączysz dzielenie wyrazów, słowo zostanie podzielone na sylaby i rozbite na 2 linie.
Rysunek 4. Akapit bez włączonej łamanej linii (u góry) i akapit z włączoną łamaną linią (u dołu).

Po włączeniu podział wyrazów występuje tylko w tych warunkach:

  • Słowo nie mieści się w wierszu. Jeśli używasz strategii Simple, podział na wiersze następuje tylko wtedy, gdy wiersz jest krótszy niż pojedyncze słowo.
  • Na urządzeniu ustawiony jest odpowiedni region, a odpowiednie dzielenie wyrazów jest określane za pomocą słowników obecnych w systemie.