Styl akapitu

Z tej strony dowiesz się, jak nadać styl tekstowi w akapicie. 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 Text, w zależności od preferowanej orientacji tekstu w danym języku. 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 w 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 konstruktor z funkcją ochrony typu, który ułatwia tworzenie: buildAnnotatedString. W tym fragmencie kodu parametr buildAnnotatedString służy do ustawiania parametru 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")
            }
        }
    )
}

3 akapity w 3 różnych stylach: niebieski, czerwony i 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” (przeskalowane piksele). Więcej informacji o wybieraniu odpowiedniej jednostki tekstowej znajdziesz w artykule TextUnit.

Obraz pokazujący wysokość linii jako pomiar na podstawie linii bezpośrednio nad nią i pod nią.
Rysunek 1. Aby dostosować tekst w ramach zestawu lineHeight, użyj opcji Wyrównanie i Obcinanie. W razie potrzeby możesz też przyciąć nadmiar wolnego miejsca.

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 określonej przez wysokość wiersza. W każdym wierszu możesz wyrównać tekst do góry, do dołu, do środka lub proporcjonalnie. Opcja LineHeightStyle.Trim pozwala pozostawić lub usunąć dodatkową spację na początku pierwszego wiersza i na końcu ostatniego wiersza tekstu wygenerowanego na podstawie wszelkich korekt 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 Ilustracja pokazująca styl LineHeightStyle.Trim.Both
LineHeightStyle.Trim.None LineHeightStyle.Trim.Both
Ilustracja pokazująca styl LineHeightStyle.Trim.FirstLineTop Obraz pokazujący styl LineHeightStyle.Trim.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 przełamania wiersza chcesz zastosować. Dostępne wstępnie typy dzielenia wiersza:

  • Simple – szybkie, podstawowe przerywanie linii. Zalecane w przypadku pól tekstowych.
  • Heading – przełamanie wiersza z mniej rygorystycznymi zasadami przełamywania. Zalecane 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 zarówno tagu Simple, jak i tagu Paragraph, aby określić sposób dzielenia 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, który pokazuje 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.

Dostosowywanie podziałów wierszy

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

  • Balanced – próba wyrównania długości wierszy tekstu, a także zastosowanie automatycznego dzielenia wyrazów, jeśli jest włączone. Zaleca się używanie ich na małych ekranach, takich jak zegarki, aby zmaksymalizować wyświetlany tekst.
  • HighQuality – optymalizuje akapit, aby tekst był bardziej czytelny, w tym łamie wyrazy, jeśli ta opcja jest włączona. (powinno być domyślne dla wszystkich wartości innych niż Balanced lub Simple).
  • Simple – podstawowa, szybka strategia. Jeśli ta opcja jest włączona, podział wyrazów jest stosowany tylko w przypadku wyrazów, które nie mieszczą się na jednej linii. 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 za pomocą strategii Balancedłamania wiersza:

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 z równomiernym rozbijaniem wierszy ma bardziej spójne długości wierszy niż domyślny.
Rysunek 2. Akapit sformatowany za pomocą Balanced strategii dzielenia wierszy (na górze) w porównaniu z akapitem sformatowanym bez strategii dzielenia wierszy.

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 wiersza.

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ł wiersza jest oparty 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 rygoryzmu i podziału wyrazów w porównaniu z tekstem domyślnym.
Rysunek 3. Tekst sformatowany za pomocą ustawień Strictness i WordBreak (góra) w porównaniu z tekstem sformatowanym tylko za pomocą LineBreak.Heading (dół).

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

Akapit bez włączonego dzielenia wyrazów i akapit z włączonym dzieleniem wyrazów.
  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.